mesa: remove _mesa from static framebuffer object function
[mesa.git] / src / mesa / main / samplerobj.c
index 8f8d87b90e8ffa1996ccc9bddae47e0fc2c9fcf0..63beaf1abba899132e52a1729d859c2d275d1b07 100644 (file)
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
 
 
 #include "main/enums.h"
 #include "main/hash.h"
 #include "main/macros.h"
-#include "main/mfeatures.h"
 #include "main/mtypes.h"
 #include "main/samplerobj.h"
 
 
-static struct gl_sampler_object *
+struct gl_sampler_object *
 _mesa_lookup_samplerobj(struct gl_context *ctx, GLuint name)
 {
    if (name == 0)
@@ -50,60 +50,58 @@ _mesa_lookup_samplerobj(struct gl_context *ctx, GLuint name)
          _mesa_HashLookup(ctx->Shared->SamplerObjects, name);
 }
 
+static inline struct gl_sampler_object *
+lookup_samplerobj_locked(struct gl_context *ctx, GLuint name)
+{
+   return (struct gl_sampler_object *)
+         _mesa_HashLookupLocked(ctx->Shared->SamplerObjects, name);
+}
+
+static void
+delete_sampler_object(struct gl_context *ctx,
+                      struct gl_sampler_object *sampObj)
+{
+   mtx_destroy(&sampObj->Mutex);
+   free(sampObj->Label);
+   free(sampObj);
+}
 
 /**
  * Handle reference counting.
  */
 void
-_mesa_reference_sampler_object(struct gl_context *ctx,
-                               struct gl_sampler_object **ptr,
-                               struct gl_sampler_object *samp)
+_mesa_reference_sampler_object_(struct gl_context *ctx,
+                                struct gl_sampler_object **ptr,
+                                struct gl_sampler_object *samp)
 {
-   if (*ptr == samp)
-      return;
+   assert(*ptr != samp); /* The inline wrapper should prevent no-op calls */
 
    if (*ptr) {
       /* Unreference the old sampler */
       GLboolean deleteFlag = GL_FALSE;
       struct gl_sampler_object *oldSamp = *ptr;
 
-      /*_glthread_LOCK_MUTEX(oldSamp->Mutex);*/
-      ASSERT(oldSamp->RefCount > 0);
+      mtx_lock(&oldSamp->Mutex);
+      assert(oldSamp->RefCount > 0);
       oldSamp->RefCount--;
-#if 0
-      printf("SamplerObj %p %d DECR to %d\n",
-             (void *) oldSamp, oldSamp->Name, oldSamp->RefCount);
-#endif
       deleteFlag = (oldSamp->RefCount == 0);
-      /*_glthread_UNLOCK_MUTEX(oldSamp->Mutex);*/
+      mtx_unlock(&oldSamp->Mutex);
 
-      if (deleteFlag) {
-        ASSERT(ctx->Driver.DeleteSamplerObject);
-         ctx->Driver.DeleteSamplerObject(ctx, oldSamp);
-      }
+      if (deleteFlag)
+         delete_sampler_object(ctx, oldSamp);
 
       *ptr = NULL;
    }
-   ASSERT(!*ptr);
+   assert(!*ptr);
 
    if (samp) {
       /* reference new sampler */
-      /*_glthread_LOCK_MUTEX(samp->Mutex);*/
-      if (samp->RefCount == 0) {
-         /* this sampler's being deleted (look just above) */
-         /* Not sure this can every really happen.  Warn if it does. */
-         _mesa_problem(NULL, "referencing deleted sampler object");
-         *ptr = NULL;
-      }
-      else {
-         samp->RefCount++;
-#if 0
-         printf("SamplerObj %p %d INCR to %d\n",
-                (void *) samp, samp->Name, samp->RefCount);
-#endif
-         *ptr = samp;
-      }
-      /*_glthread_UNLOCK_MUTEX(samp->Mutex);*/
+      mtx_lock(&samp->Mutex);
+      assert(samp->RefCount > 0);
+
+      samp->RefCount++;
+      *ptr = samp;
+      mtx_unlock(&samp->Mutex);
    }
 }
 
@@ -111,9 +109,10 @@ _mesa_reference_sampler_object(struct gl_context *ctx,
 /**
  * Initialize the fields of the given sampler object.
  */
-void
+static void
 _mesa_init_sampler_object(struct gl_sampler_object *sampObj, GLuint name)
 {
+   mtx_init(&sampObj->Mutex, mtx_plain);
    sampObj->Name = name;
    sampObj->RefCount = 1;
    sampObj->WrapS = GL_REPEAT;
@@ -131,13 +130,10 @@ _mesa_init_sampler_object(struct gl_sampler_object *sampObj, GLuint name)
    sampObj->MaxAnisotropy = 1.0F;
    sampObj->CompareMode = GL_NONE;
    sampObj->CompareFunc = GL_LEQUAL;
-   sampObj->CompareFailValue = 0.0;
    sampObj->sRGBDecode = GL_DECODE_EXT;
    sampObj->CubeMapSeamless = GL_FALSE;
-   sampObj->DepthMode = 0;
 }
 
-
 /**
  * Fallback for ctx->Driver.NewSamplerObject();
  */
@@ -151,57 +147,60 @@ _mesa_new_sampler_object(struct gl_context *ctx, GLuint name)
    return sampObj;
 }
 
-
-/**
- * Fallback for ctx->Driver.DeleteSamplerObject();
- */
-void
-_mesa_delete_sampler_object(struct gl_context *ctx,
-                            struct gl_sampler_object *sampObj)
-{
-   FREE(sampObj);
-}
-
-
-static void GLAPIENTRY
-_mesa_GenSamplers(GLsizei count, GLuint *samplers)
+static void
+create_samplers(struct gl_context *ctx, GLsizei count, GLuint *samplers,
+                const char *caller)
 {
-   GET_CURRENT_CONTEXT(ctx);
    GLuint first;
    GLint i;
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
    if (MESA_VERBOSE & VERBOSE_API)
-      _mesa_debug(ctx, "glGenSamplers(%d)\n", count);
+      _mesa_debug(ctx, "%s(%d)\n", caller, count);
 
    if (count < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glGenSamplers");
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", caller);
       return;
    }
 
    if (!samplers)
       return;
 
+   _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
+
    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->SamplerObjects, count);
 
    /* Insert the ID and pointer to new sampler object into hash table */
    for (i = 0; i < count; i++) {
       struct gl_sampler_object *sampObj =
          ctx->Driver.NewSamplerObject(ctx, first + i);
-      _mesa_HashInsert(ctx->Shared->SamplerObjects, first + i, sampObj);
+      _mesa_HashInsertLocked(ctx->Shared->SamplerObjects, first + i, sampObj);
       samplers[i] = first + i;
    }
+
+   _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
 }
 
+void GLAPIENTRY
+_mesa_GenSamplers(GLsizei count, GLuint *samplers)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_samplers(ctx, count, samplers, "glGenSamplers");
+}
 
-static void GLAPIENTRY
+void GLAPIENTRY
+_mesa_CreateSamplers(GLsizei count, GLuint *samplers)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   create_samplers(ctx, count, samplers, "glCreateSamplers");
+}
+
+
+void GLAPIENTRY
 _mesa_DeleteSamplers(GLsizei count, const GLuint *samplers)
 {
    GET_CURRENT_CONTEXT(ctx);
    GLsizei i;
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
    FLUSH_VERTICES(ctx, 0);
 
    if (count < 0) {
@@ -209,43 +208,58 @@ _mesa_DeleteSamplers(GLsizei count, const GLuint *samplers)
       return;
    }
 
-   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+   _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
 
    for (i = 0; i < count; i++) {
       if (samplers[i]) {
+         GLuint j;
          struct gl_sampler_object *sampObj =
-            _mesa_lookup_samplerobj(ctx, samplers[i]);
+            lookup_samplerobj_locked(ctx, samplers[i]);
+   
          if (sampObj) {
+            /* If the sampler is currently bound, unbind it. */
+            for (j = 0; j < ctx->Const.MaxCombinedTextureImageUnits; j++) {
+               if (ctx->Texture.Unit[j].Sampler == sampObj) {
+                  FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
+                  _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[j].Sampler, NULL);
+               }
+            }
+
             /* The ID is immediately freed for re-use */
-            _mesa_HashRemove(ctx->Shared->SamplerObjects, samplers[i]);
+            _mesa_HashRemoveLocked(ctx->Shared->SamplerObjects, samplers[i]);
             /* But the object exists until its reference count goes to zero */
             _mesa_reference_sampler_object(ctx, &sampObj, NULL);
          }
       }
    }
 
-   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+   _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
 }
 
 
-static GLboolean GLAPIENTRY
+GLboolean GLAPIENTRY
 _mesa_IsSampler(GLuint sampler)
 {
-   struct gl_sampler_object *sampObj;
    GET_CURRENT_CONTEXT(ctx);
 
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
 
-   if (sampler == 0)
-      return GL_FALSE;
+   return _mesa_lookup_samplerobj(ctx, sampler) != NULL;
+}
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
+void
+_mesa_bind_sampler(struct gl_context *ctx, GLuint unit,
+                   struct gl_sampler_object *sampObj)
+{
+   if (ctx->Texture.Unit[unit].Sampler != sampObj) {
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
+   }
 
-   return sampObj != NULL;
+   _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[unit].Sampler,
+                                  sampObj);
 }
 
-
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_BindSampler(GLuint unit, GLuint sampler)
 {
    struct gl_sampler_object *sampObj;
@@ -271,13 +285,107 @@ _mesa_BindSampler(GLuint unit, GLuint sampler)
       }
    }
    
-   if (ctx->Texture.Unit[unit].Sampler != sampObj) {
-      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+   /* bind new sampler */
+   _mesa_bind_sampler(ctx, unit, sampObj);
+}
+
+
+void GLAPIENTRY
+_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   GLint i;
+
+   /* The ARB_multi_bind spec says:
+    *
+    *   "An INVALID_OPERATION error is generated if <first> + <count> is
+    *    greater than the number of texture image units supported by
+    *    the implementation."
+    */
+   if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glBindSamplers(first=%u + count=%d > the value of "
+                  "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
+                  first, count, ctx->Const.MaxCombinedTextureImageUnits);
+      return;
    }
 
-   /* bind new sampler */
-   _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[unit].Sampler,
-                                  sampObj);
+   FLUSH_VERTICES(ctx, 0);
+
+   if (samplers) {
+      /* Note that the error semantics for multi-bind commands differ from
+       * those of other GL commands.
+       *
+       * The Issues section in the ARB_multi_bind spec says:
+       *
+       *    "(11) Typically, OpenGL specifies that if an error is generated by
+       *          a command, that command has no effect.  This is somewhat
+       *          unfortunate for multi-bind commands, because it would require
+       *          a first pass to scan the entire list of bound objects for
+       *          errors and then a second pass to actually perform the
+       *          bindings.  Should we have different error semantics?
+       *
+       *       RESOLVED:  Yes.  In this specification, when the parameters for
+       *       one of the <count> binding points are invalid, that binding
+       *       point is not updated and an error will be generated.  However,
+       *       other binding points in the same command will be updated if
+       *       their parameters are valid and no other error occurs."
+       */
+
+      _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
+
+      for (i = 0; i < count; i++) {
+         const GLuint unit = first + i;
+         struct gl_sampler_object * const currentSampler =
+             ctx->Texture.Unit[unit].Sampler;
+         struct gl_sampler_object *sampObj;
+
+         if (samplers[i] != 0) {
+            if (currentSampler && currentSampler->Name == samplers[i])
+               sampObj = currentSampler;
+            else
+               sampObj = lookup_samplerobj_locked(ctx, samplers[i]);
+
+            /* The ARB_multi_bind spec says:
+             *
+             *    "An INVALID_OPERATION error is generated if any value
+             *     in <samplers> is not zero or the name of an existing
+             *     sampler object (per binding)."
+             */
+            if (!sampObj) {
+               _mesa_error(ctx, GL_INVALID_OPERATION,
+                           "glBindSamplers(samplers[%d]=%u is not zero or "
+                           "the name of an existing sampler object)",
+                           i, samplers[i]);
+               continue;
+            }
+         } else {
+            sampObj = NULL;
+         }
+
+         /* Bind the new sampler */
+         if (sampObj != currentSampler) {
+            _mesa_reference_sampler_object(ctx,
+                                           &ctx->Texture.Unit[unit].Sampler,
+                                           sampObj);
+            ctx->NewState |= _NEW_TEXTURE_OBJECT;
+         }
+      }
+
+      _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
+   } else {
+      /* Unbind all samplers in the range <first> through <first>+<count>-1 */
+      for (i = 0; i < count; i++) {
+         const GLuint unit = first + i;
+
+         if (ctx->Texture.Unit[unit].Sampler) {
+            _mesa_reference_sampler_object(ctx,
+                                           &ctx->Texture.Unit[unit].Sampler,
+                                           NULL);
+            ctx->NewState |= _NEW_TEXTURE_OBJECT;
+         }
+      }
+   }
 }
 
 
@@ -294,15 +402,14 @@ validate_texture_wrap_mode(struct gl_context *ctx, GLenum wrap)
    case GL_CLAMP:
    case GL_CLAMP_TO_EDGE:
    case GL_REPEAT:
+   case GL_MIRRORED_REPEAT:
       return GL_TRUE;
    case GL_CLAMP_TO_BORDER:
       return e->ARB_texture_border_clamp;
-   case GL_MIRRORED_REPEAT:
-      return e->ARB_texture_mirrored_repeat;
    case GL_MIRROR_CLAMP_EXT:
       return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp;
    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
-      return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp;
+      return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp || e->ARB_texture_mirror_clamp_to_edge;
    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
       return e->EXT_texture_mirror_clamp;
    default:
@@ -314,12 +421,28 @@ validate_texture_wrap_mode(struct gl_context *ctx, GLenum wrap)
 /**
  * This is called just prior to changing any sampler object state.
  */
-static INLINE void
+static inline void
 flush(struct gl_context *ctx)
 {
-   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+   FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
 }
 
+void
+_mesa_set_sampler_wrap(struct gl_context *ctx, struct gl_sampler_object *samp,
+                       GLenum s, GLenum t, GLenum r)
+{
+   assert(validate_texture_wrap_mode(ctx, s));
+   assert(validate_texture_wrap_mode(ctx, t));
+   assert(validate_texture_wrap_mode(ctx, r));
+
+   if (samp->WrapS == s && samp->WrapT == t && samp->WrapR == r)
+      return;
+
+   flush(ctx);
+   samp->WrapS = s;
+   samp->WrapT = t;
+   samp->WrapR = r;
+}
 
 #define INVALID_PARAM 0x100
 #define INVALID_PNAME 0x101
@@ -369,6 +492,27 @@ set_sampler_wrap_r(struct gl_context *ctx, struct gl_sampler_object *samp,
    return INVALID_PARAM;
 }
 
+void
+_mesa_set_sampler_filters(struct gl_context *ctx,
+                          struct gl_sampler_object *samp,
+                          GLenum min_filter, GLenum mag_filter)
+{
+   assert(min_filter == GL_NEAREST ||
+          min_filter == GL_LINEAR ||
+          min_filter == GL_NEAREST_MIPMAP_NEAREST ||
+          min_filter == GL_LINEAR_MIPMAP_NEAREST ||
+          min_filter == GL_NEAREST_MIPMAP_LINEAR ||
+          min_filter == GL_LINEAR_MIPMAP_LINEAR);
+   assert(mag_filter == GL_NEAREST ||
+          mag_filter == GL_LINEAR);
+
+   if (samp->MinFilter == min_filter && samp->MagFilter == mag_filter)
+      return;
+
+   flush(ctx);
+   samp->MinFilter = min_filter;
+   samp->MagFilter = mag_filter;
+}
 
 static GLuint
 set_sampler_min_filter(struct gl_context *ctx, struct gl_sampler_object *samp,
@@ -497,8 +641,12 @@ static GLuint
 set_sampler_compare_mode(struct gl_context *ctx,
                          struct gl_sampler_object *samp, GLint param)
 {
+    /* If GL_ARB_shadow is not supported, don't report an error.  The
+     * sampler object extension spec isn't clear on this extension interaction.
+     * Silences errors with Wine on older GPUs such as R200.
+     */
    if (!ctx->Extensions.ARB_shadow)
-      return INVALID_PNAME;
+      return GL_FALSE;
 
    if (samp->CompareMode == param)
       return GL_FALSE;
@@ -518,8 +666,12 @@ static GLuint
 set_sampler_compare_func(struct gl_context *ctx,
                          struct gl_sampler_object *samp, GLint param)
 {
+    /* If GL_ARB_shadow is not supported, don't report an error.  The
+     * sampler object extension spec isn't clear on this extension interaction.
+     * Silences errors with Wine on older GPUs such as R200.
+     */
    if (!ctx->Extensions.ARB_shadow)
-      return INVALID_PNAME;
+      return GL_FALSE;
 
    if (samp->CompareFunc == param)
       return GL_FALSE;
@@ -527,21 +679,15 @@ set_sampler_compare_func(struct gl_context *ctx,
    switch (param) {
    case GL_LEQUAL:
    case GL_GEQUAL:
-      flush(ctx);
-      samp->CompareFunc = param;
-      return GL_TRUE;
    case GL_EQUAL:
    case GL_NOTEQUAL:
    case GL_LESS:
    case GL_GREATER:
    case GL_ALWAYS:
    case GL_NEVER:
-      if (ctx->Extensions.EXT_shadow_funcs) {
-         flush(ctx);
-         samp->CompareFunc = param;
-         return GL_TRUE;
-      }
-      /* fall-through */
+      flush(ctx);
+      samp->CompareFunc = param;
+      return GL_TRUE;
    default:
       return INVALID_PARAM;
    }
@@ -558,7 +704,7 @@ set_sampler_max_anisotropy(struct gl_context *ctx,
    if (samp->MaxAnisotropy == param)
       return GL_FALSE;
 
-   if (param < 1.0)
+   if (param < 1.0F)
       return INVALID_VALUE;
 
    flush(ctx);
@@ -572,7 +718,8 @@ static GLuint
 set_sampler_cube_map_seamless(struct gl_context *ctx,
                               struct gl_sampler_object *samp, GLboolean param)
 {
-   if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
+   if (!_mesa_is_desktop_gl(ctx)
+       || !ctx->Extensions.AMD_seamless_cubemap_per_texture)
       return INVALID_PNAME;
 
    if (samp->CubeMapSeamless == param)
@@ -586,20 +733,67 @@ set_sampler_cube_map_seamless(struct gl_context *ctx,
    return GL_TRUE;
 }
 
+void
+_mesa_set_sampler_srgb_decode(struct gl_context *ctx,
+                              struct gl_sampler_object *samp, GLenum param)
+{
+   assert(param == GL_DECODE_EXT || param == GL_SKIP_DECODE_EXT);
+
+   flush(ctx);
+   samp->sRGBDecode = param;
+}
+
+static GLuint
+set_sampler_srgb_decode(struct gl_context *ctx,
+                              struct gl_sampler_object *samp, GLenum param)
+{
+   if (!ctx->Extensions.EXT_texture_sRGB_decode)
+      return INVALID_PNAME;
+
+   if (samp->sRGBDecode == param)
+      return GL_FALSE;
+
+   if (param != GL_DECODE_EXT && param != GL_SKIP_DECODE_EXT)
+      return INVALID_VALUE;
+
+   flush(ctx);
+   samp->sRGBDecode = param;
+   return GL_TRUE;
+}
+
+static struct gl_sampler_object *
+sampler_parameter_error_check(struct gl_context *ctx, GLuint sampler,
+                              const char *name)
+{
+   struct gl_sampler_object *sampObj;
+
+   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
+   if (!sampObj) {
+      /* OpenGL 4.5 spec, section "8.2 Sampler Objects", page 176 of the PDF
+       * states:
+       *
+       *    "An INVALID_OPERATION error is generated if sampler is not the name
+       *    of a sampler object previously returned from a call to
+       *    GenSamplers."
+       */
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid sampler)", name);
+      return NULL;
+   }
 
-static void GLAPIENTRY
+   return sampObj;
+}
+
+void GLAPIENTRY
 _mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
 {
    struct gl_sampler_object *sampObj;
    GLuint res;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameteri(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glSamplerParameteri");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -638,6 +832,9 @@ _mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
    case GL_TEXTURE_CUBE_MAP_SEAMLESS:
       res = set_sampler_cube_map_seamless(ctx, sampObj, param);
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      res = set_sampler_srgb_decode(ctx, sampObj, param);
+      break;
    case GL_TEXTURE_BORDER_COLOR:
       /* fall-through */
    default:
@@ -653,7 +850,7 @@ _mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
       break;
    case INVALID_PNAME:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteri(pname=%s)\n",
-                  _mesa_lookup_enum_by_nr(pname));
+                  _mesa_enum_to_string(pname));
       break;
    case INVALID_PARAM:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteri(param=%d)\n",
@@ -669,21 +866,17 @@ _mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
 }
 
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
 {
    struct gl_sampler_object *sampObj;
    GLuint res;
    GET_CURRENT_CONTEXT(ctx);
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterf(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glSamplerParameterf");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -722,6 +915,9 @@ _mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
    case GL_TEXTURE_CUBE_MAP_SEAMLESS:
       res = set_sampler_cube_map_seamless(ctx, sampObj, (GLboolean) param);
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) param);
+      break;
    case GL_TEXTURE_BORDER_COLOR:
       /* fall-through */
    default:
@@ -737,7 +933,7 @@ _mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
       break;
    case INVALID_PNAME:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterf(pname=%s)\n",
-                  _mesa_lookup_enum_by_nr(pname));
+                  _mesa_enum_to_string(pname));
       break;
    case INVALID_PARAM:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterf(param=%f)\n",
@@ -752,19 +948,17 @@ _mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
    }
 }
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *params)
 {
    struct gl_sampler_object *sampObj;
    GLuint res;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameteriv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glSamplerParameteriv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -803,6 +997,9 @@ _mesa_SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *params)
    case GL_TEXTURE_CUBE_MAP_SEAMLESS:
       res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      res = set_sampler_srgb_decode(ctx, sampObj, params[0]);
+      break;
    case GL_TEXTURE_BORDER_COLOR:
       {
          GLfloat c[4];
@@ -826,7 +1023,7 @@ _mesa_SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *params)
       break;
    case INVALID_PNAME:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteriv(pname=%s)\n",
-                  _mesa_lookup_enum_by_nr(pname));
+                  _mesa_enum_to_string(pname));
       break;
    case INVALID_PARAM:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteriv(param=%d)\n",
@@ -841,21 +1038,17 @@ _mesa_SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *params)
    }
 }
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *params)
 {
    struct gl_sampler_object *sampObj;
    GLuint res;
    GET_CURRENT_CONTEXT(ctx);
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterfv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glSamplerParameterfv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -894,6 +1087,9 @@ _mesa_SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *params)
    case GL_TEXTURE_CUBE_MAP_SEAMLESS:
       res = set_sampler_cube_map_seamless(ctx, sampObj, (GLboolean) params[0]);
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
+      break;
    case GL_TEXTURE_BORDER_COLOR:
       res = set_sampler_border_colorf(ctx, sampObj, params);
       break;
@@ -910,7 +1106,7 @@ _mesa_SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *params)
       break;
    case INVALID_PNAME:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterfv(pname=%s)\n",
-                  _mesa_lookup_enum_by_nr(pname));
+                  _mesa_enum_to_string(pname));
       break;
    case INVALID_PARAM:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterfv(param=%f)\n",
@@ -925,19 +1121,17 @@ _mesa_SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *params)
    }
 }
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint *params)
 {
    struct gl_sampler_object *sampObj;
    GLuint res;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterIiv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glSamplerParameterIiv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -976,6 +1170,9 @@ _mesa_SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint *params)
    case GL_TEXTURE_CUBE_MAP_SEAMLESS:
       res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
+      break;
    case GL_TEXTURE_BORDER_COLOR:
       res = set_sampler_border_colori(ctx, sampObj, params);
       break;
@@ -992,7 +1189,7 @@ _mesa_SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint *params)
       break;
    case INVALID_PNAME:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIiv(pname=%s)\n",
-                  _mesa_lookup_enum_by_nr(pname));
+                  _mesa_enum_to_string(pname));
       break;
    case INVALID_PARAM:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIiv(param=%d)\n",
@@ -1008,19 +1205,17 @@ _mesa_SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint *params)
 }
 
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint *params)
 {
    struct gl_sampler_object *sampObj;
    GLuint res;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterIuiv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glSamplerParameterIuiv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -1059,6 +1254,9 @@ _mesa_SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint *params)
    case GL_TEXTURE_CUBE_MAP_SEAMLESS:
       res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
+      break;
    case GL_TEXTURE_BORDER_COLOR:
       res = set_sampler_border_colorui(ctx, sampObj, params);
       break;
@@ -1075,7 +1273,7 @@ _mesa_SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint *params)
       break;
    case INVALID_PNAME:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIuiv(pname=%s)\n",
-                  _mesa_lookup_enum_by_nr(pname));
+                  _mesa_enum_to_string(pname));
       break;
    case INVALID_PARAM:
       _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIuiv(param=%u)\n",
@@ -1091,18 +1289,16 @@ _mesa_SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint *params)
 }
 
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
 {
    struct gl_sampler_object *sampObj;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glGetSamplerParameteriv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glGetSamplerParameteriv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -1121,26 +1317,34 @@ _mesa_GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
       *params = sampObj->MagFilter;
       break;
    case GL_TEXTURE_MIN_LOD:
-      *params = (GLint) sampObj->MinLod;
+      /* GL spec 'Data Conversions' section specifies that floating-point
+       * value in integer Get function is rounded to nearest integer
+       */
+      *params = IROUND(sampObj->MinLod);
       break;
    case GL_TEXTURE_MAX_LOD:
-      *params = (GLint) sampObj->MaxLod;
+      /* GL spec 'Data Conversions' section specifies that floating-point
+       * value in integer Get function is rounded to nearest integer
+       */
+      *params = IROUND(sampObj->MaxLod);
       break;
    case GL_TEXTURE_LOD_BIAS:
-      *params = (GLint) sampObj->LodBias;
+      /* GL spec 'Data Conversions' section specifies that floating-point
+       * value in integer Get function is rounded to nearest integer
+       */
+      *params = IROUND(sampObj->LodBias);
       break;
    case GL_TEXTURE_COMPARE_MODE:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = sampObj->CompareMode;
       break;
    case GL_TEXTURE_COMPARE_FUNC:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = sampObj->CompareFunc;
       break;
    case GL_TEXTURE_MAX_ANISOTROPY_EXT:
-      *params = (GLint) sampObj->MaxAnisotropy;
+      /* GL spec 'Data Conversions' section specifies that floating-point
+       * value in integer Get function is rounded to nearest integer
+       */
+      *params = IROUND(sampObj->MaxAnisotropy);
       break;
    case GL_TEXTURE_BORDER_COLOR:
       params[0] = FLOAT_TO_INT(sampObj->BorderColor.f[0]);
@@ -1153,6 +1357,11 @@ _mesa_GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
          goto invalid_pname;
       *params = sampObj->CubeMapSeamless;
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      if (!ctx->Extensions.EXT_texture_sRGB_decode)
+         goto invalid_pname;
+      *params = (GLenum) sampObj->sRGBDecode;
+      break;
    default:
       goto invalid_pname;
    }
@@ -1160,22 +1369,20 @@ _mesa_GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
 
 invalid_pname:
    _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameteriv(pname=%s)",
-               _mesa_lookup_enum_by_nr(pname));
+               _mesa_enum_to_string(pname));
 }
 
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
 {
    struct gl_sampler_object *sampObj;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glGetSamplerParameterfv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glGetSamplerParameterfv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -1203,13 +1410,9 @@ _mesa_GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
       *params = sampObj->LodBias;
       break;
    case GL_TEXTURE_COMPARE_MODE:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = (GLfloat) sampObj->CompareMode;
       break;
    case GL_TEXTURE_COMPARE_FUNC:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = (GLfloat) sampObj->CompareFunc;
       break;
    case GL_TEXTURE_MAX_ANISOTROPY_EXT:
@@ -1226,6 +1429,11 @@ _mesa_GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
          goto invalid_pname;
       *params = (GLfloat) sampObj->CubeMapSeamless;
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      if (!ctx->Extensions.EXT_texture_sRGB_decode)
+         goto invalid_pname;
+      *params = (GLfloat) sampObj->sRGBDecode;
+      break;
    default:
       goto invalid_pname;
    }
@@ -1233,23 +1441,20 @@ _mesa_GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
 
 invalid_pname:
    _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterfv(pname=%s)",
-               _mesa_lookup_enum_by_nr(pname));
+               _mesa_enum_to_string(pname));
 }
 
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint *params)
 {
    struct gl_sampler_object *sampObj;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glGetSamplerParameterIiv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glGetSamplerParameterIiv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -1277,13 +1482,9 @@ _mesa_GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint *params)
       *params = (GLint) sampObj->LodBias;
       break;
    case GL_TEXTURE_COMPARE_MODE:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = sampObj->CompareMode;
       break;
    case GL_TEXTURE_COMPARE_FUNC:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = sampObj->CompareFunc;
       break;
    case GL_TEXTURE_MAX_ANISOTROPY_EXT:
@@ -1300,6 +1501,11 @@ _mesa_GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint *params)
          goto invalid_pname;
       *params = sampObj->CubeMapSeamless;
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      if (!ctx->Extensions.EXT_texture_sRGB_decode)
+         goto invalid_pname;
+      *params = (GLenum) sampObj->sRGBDecode;
+      break;
    default:
       goto invalid_pname;
    }
@@ -1307,23 +1513,20 @@ _mesa_GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint *params)
 
 invalid_pname:
    _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterIiv(pname=%s)",
-               _mesa_lookup_enum_by_nr(pname));
+               _mesa_enum_to_string(pname));
 }
 
 
-static void GLAPIENTRY
+void GLAPIENTRY
 _mesa_GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint *params)
 {
    struct gl_sampler_object *sampObj;
    GET_CURRENT_CONTEXT(ctx);
 
-   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
-   if (!sampObj) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glGetSamplerParameterIuiv(sampler %u)",
-                  sampler);
+   sampObj = sampler_parameter_error_check(ctx, sampler,
+                                           "glGetSamplerParameterIuiv");
+   if (!sampObj)
       return;
-   }
 
    switch (pname) {
    case GL_TEXTURE_WRAP_S:
@@ -1351,13 +1554,9 @@ _mesa_GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint *params)
       *params = (GLuint) sampObj->LodBias;
       break;
    case GL_TEXTURE_COMPARE_MODE:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = sampObj->CompareMode;
       break;
    case GL_TEXTURE_COMPARE_FUNC:
-      if (!ctx->Extensions.ARB_shadow)
-         goto invalid_pname;
       *params = sampObj->CompareFunc;
       break;
    case GL_TEXTURE_MAX_ANISOTROPY_EXT:
@@ -1374,6 +1573,11 @@ _mesa_GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint *params)
          goto invalid_pname;
       *params = sampObj->CubeMapSeamless;
       break;
+   case GL_TEXTURE_SRGB_DECODE_EXT:
+      if (!ctx->Extensions.EXT_texture_sRGB_decode)
+         goto invalid_pname;
+      *params = (GLenum) sampObj->sRGBDecode;
+      break;
    default:
       goto invalid_pname;
    }
@@ -1381,7 +1585,7 @@ _mesa_GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint *params)
 
 invalid_pname:
    _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterIuiv(pname=%s)",
-               _mesa_lookup_enum_by_nr(pname));
+               _mesa_enum_to_string(pname));
 }
 
 
@@ -1389,25 +1593,4 @@ void
 _mesa_init_sampler_object_functions(struct dd_function_table *driver)
 {
    driver->NewSamplerObject = _mesa_new_sampler_object;
-   driver->DeleteSamplerObject = _mesa_delete_sampler_object;
-}
-
-
-void
-_mesa_init_sampler_object_dispatch(struct _glapi_table *disp)
-{
-   SET_GenSamplers(disp, _mesa_GenSamplers);
-   SET_DeleteSamplers(disp, _mesa_DeleteSamplers);
-   SET_IsSampler(disp, _mesa_IsSampler);
-   SET_BindSampler(disp, _mesa_BindSampler);
-   SET_SamplerParameteri(disp, _mesa_SamplerParameteri);
-   SET_SamplerParameterf(disp, _mesa_SamplerParameterf);
-   SET_SamplerParameteriv(disp, _mesa_SamplerParameteriv);
-   SET_SamplerParameterfv(disp, _mesa_SamplerParameterfv);
-   SET_SamplerParameterIiv(disp, _mesa_SamplerParameterIiv);
-   SET_SamplerParameterIuiv(disp, _mesa_SamplerParameterIuiv);
-   SET_GetSamplerParameteriv(disp, _mesa_GetSamplerParameteriv);
-   SET_GetSamplerParameterfv(disp, _mesa_GetSamplerParameterfv);
-   SET_GetSamplerParameterIiv(disp, _mesa_GetSamplerParameterIiv);
-   SET_GetSamplerParameterIuiv(disp, _mesa_GetSamplerParameterIuiv);
 }