1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2011  VMware, Inc.  All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26/**
27 * \file samplerobj.c
28 * \brief Functions for the GL_ARB_sampler_objects extension.
29 * \author Brian Paul
30 */
31
32
33#include "main/glheader.h"
34#include "main/context.h"
35#include "main/enums.h"
36#include "main/hash.h"
37#include "main/macros.h"
38#include "main/mtypes.h"
39#include "main/samplerobj.h"
40#include "main/texturebindless.h"
41
42
43struct gl_sampler_object *
44_mesa_lookup_samplerobj(struct gl_context *ctx, GLuint name)
45{
46   if (name == 0)
47      return NULL;
48   else
49      return (struct gl_sampler_object *)
50         _mesa_HashLookup(ctx->Shared->SamplerObjects, name);
51}
52
53static inline struct gl_sampler_object *
54lookup_samplerobj_locked(struct gl_context *ctx, GLuint name)
55{
56   return (struct gl_sampler_object *)
57         _mesa_HashLookupLocked(ctx->Shared->SamplerObjects, name);
58}
59
60static void
61delete_sampler_object(struct gl_context *ctx,
62                      struct gl_sampler_object *sampObj)
63{
64   _mesa_delete_sampler_handles(ctx, sampObj);
65   simple_mtx_destroy(&sampObj->Mutex);
66   free(sampObj->Label);
67   free(sampObj);
68}
69
70/**
71 * Handle reference counting.
72 */
73void
74_mesa_reference_sampler_object_(struct gl_context *ctx,
75                                struct gl_sampler_object **ptr,
76                                struct gl_sampler_object *samp)
77{
78   assert(*ptr != samp); /* The inline wrapper should prevent no-op calls */
79
80   if (*ptr) {
81      /* Unreference the old sampler */
82      GLboolean deleteFlag = GL_FALSE;
83      struct gl_sampler_object *oldSamp = *ptr;
84
85      simple_mtx_lock(&oldSamp->Mutex);
86      assert(oldSamp->RefCount > 0);
87      oldSamp->RefCount--;
88      deleteFlag = (oldSamp->RefCount == 0);
89      simple_mtx_unlock(&oldSamp->Mutex);
90
91      if (deleteFlag)
92         delete_sampler_object(ctx, oldSamp);
93
94      *ptr = NULL;
95   }
96   assert(!*ptr);
97
98   if (samp) {
99      /* reference new sampler */
100      simple_mtx_lock(&samp->Mutex);
101      assert(samp->RefCount > 0);
102
103      samp->RefCount++;
104      *ptr = samp;
105      simple_mtx_unlock(&samp->Mutex);
106   }
107}
108
109
110/**
111 * Initialize the fields of the given sampler object.
112 */
113static void
114_mesa_init_sampler_object(struct gl_sampler_object *sampObj, GLuint name)
115{
116   simple_mtx_init(&sampObj->Mutex, mtx_plain);
117   sampObj->Name = name;
118   sampObj->RefCount = 1;
119   sampObj->WrapS = GL_REPEAT;
120   sampObj->WrapT = GL_REPEAT;
121   sampObj->WrapR = GL_REPEAT;
122   sampObj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
123   sampObj->MagFilter = GL_LINEAR;
124   sampObj->BorderColor.f[0] = 0.0;
125   sampObj->BorderColor.f[1] = 0.0;
126   sampObj->BorderColor.f[2] = 0.0;
127   sampObj->BorderColor.f[3] = 0.0;
128   sampObj->MinLod = -1000.0F;
129   sampObj->MaxLod = 1000.0F;
130   sampObj->LodBias = 0.0F;
131   sampObj->MaxAnisotropy = 1.0F;
132   sampObj->CompareMode = GL_NONE;
133   sampObj->CompareFunc = GL_LEQUAL;
134   sampObj->sRGBDecode = GL_DECODE_EXT;
135   sampObj->CubeMapSeamless = GL_FALSE;
136   sampObj->HandleAllocated = GL_FALSE;
137
138   /* GL_ARB_bindless_texture */
139   _mesa_init_sampler_handles(sampObj);
140}
141
142/**
143 * Fallback for ctx->Driver.NewSamplerObject();
144 */
145struct gl_sampler_object *
146_mesa_new_sampler_object(struct gl_context *ctx, GLuint name)
147{
148   struct gl_sampler_object *sampObj = CALLOC_STRUCT(gl_sampler_object);
149   if (sampObj) {
150      _mesa_init_sampler_object(sampObj, name);
151   }
152   return sampObj;
153}
154
155static void
156create_samplers(struct gl_context *ctx, GLsizei count, GLuint *samplers,
157                const char *caller)
158{
159   GLuint first;
160   GLint i;
161
162   if (!samplers)
163      return;
164
165   _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
166
167   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->SamplerObjects, count);
168
169   /* Insert the ID and pointer to new sampler object into hash table */
170   for (i = 0; i < count; i++) {
171      struct gl_sampler_object *sampObj;
172      GLuint name = first + i;
173
174      sampObj = ctx->Driver.NewSamplerObject(ctx, name);
175      if (!sampObj) {
176         _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
177         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
178         return;
179      }
180
181      _mesa_HashInsertLocked(ctx->Shared->SamplerObjects, name, sampObj);
182      samplers[i] = name;
183   }
184
185   _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
186}
187
188static void
189create_samplers_err(struct gl_context *ctx, GLsizei count, GLuint *samplers,
190                    const char *caller)
191{
192
193   if (MESA_VERBOSE & VERBOSE_API)
194      _mesa_debug(ctx, "%s(%d)\n", caller, count);
195
196   if (count < 0) {
197      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", caller);
198      return;
199   }
200
201   create_samplers(ctx, count, samplers, caller);
202}
203
204void GLAPIENTRY
205_mesa_GenSamplers_no_error(GLsizei count, GLuint *samplers)
206{
207   GET_CURRENT_CONTEXT(ctx);
208   create_samplers(ctx, count, samplers, "glGenSamplers");
209}
210
211void GLAPIENTRY
212_mesa_GenSamplers(GLsizei count, GLuint *samplers)
213{
214   GET_CURRENT_CONTEXT(ctx);
215   create_samplers_err(ctx, count, samplers, "glGenSamplers");
216}
217
218void GLAPIENTRY
219_mesa_CreateSamplers_no_error(GLsizei count, GLuint *samplers)
220{
221   GET_CURRENT_CONTEXT(ctx);
222   create_samplers(ctx, count, samplers, "glCreateSamplers");
223}
224
225void GLAPIENTRY
226_mesa_CreateSamplers(GLsizei count, GLuint *samplers)
227{
228   GET_CURRENT_CONTEXT(ctx);
229   create_samplers_err(ctx, count, samplers, "glCreateSamplers");
230}
231
232
233static void
234delete_samplers(struct gl_context *ctx, GLsizei count, const GLuint *samplers)
235{
236   FLUSH_VERTICES(ctx, 0);
237
238   _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
239
240   for (GLsizei i = 0; i < count; i++) {
241      if (samplers[i]) {
242         GLuint j;
243         struct gl_sampler_object *sampObj =
244            lookup_samplerobj_locked(ctx, samplers[i]);
245
246         if (sampObj) {
247            /* If the sampler is currently bound, unbind it. */
248            for (j = 0; j < ctx->Const.MaxCombinedTextureImageUnits; j++) {
249               if (ctx->Texture.Unit[j].Sampler == sampObj) {
250                  FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
251                  _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[j].Sampler, NULL);
252               }
253            }
254
255            /* The ID is immediately freed for re-use */
256            _mesa_HashRemoveLocked(ctx->Shared->SamplerObjects, samplers[i]);
257            /* But the object exists until its reference count goes to zero */
258            _mesa_reference_sampler_object(ctx, &sampObj, NULL);
259         }
260      }
261   }
262
263   _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
264}
265
266
267void GLAPIENTRY
268_mesa_DeleteSamplers_no_error(GLsizei count, const GLuint *samplers)
269{
270   GET_CURRENT_CONTEXT(ctx);
271   delete_samplers(ctx, count, samplers);
272}
273
274
275void GLAPIENTRY
276_mesa_DeleteSamplers(GLsizei count, const GLuint *samplers)
277{
278   GET_CURRENT_CONTEXT(ctx);
279
280   if (count < 0) {
281      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteSamplers(count)");
282      return;
283   }
284
285   delete_samplers(ctx, count, samplers);
286}
287
288
289GLboolean GLAPIENTRY
290_mesa_IsSampler(GLuint sampler)
291{
292   GET_CURRENT_CONTEXT(ctx);
293
294   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
295
296   return _mesa_lookup_samplerobj(ctx, sampler) != NULL;
297}
298
299void
300_mesa_bind_sampler(struct gl_context *ctx, GLuint unit,
301                   struct gl_sampler_object *sampObj)
302{
303   if (ctx->Texture.Unit[unit].Sampler != sampObj) {
304      FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
305   }
306
307   _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[unit].Sampler,
308                                  sampObj);
309}
310
311static ALWAYS_INLINE void
312bind_sampler(struct gl_context *ctx, GLuint unit, GLuint sampler, bool no_error)
313{
314   struct gl_sampler_object *sampObj;
315
316   if (sampler == 0) {
317      /* Use the default sampler object, the one contained in the texture
318       * object.
319       */
320      sampObj = NULL;
321   } else {
322      /* user-defined sampler object */
323      sampObj = _mesa_lookup_samplerobj(ctx, sampler);
324      if (!no_error && !sampObj) {
325         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindSampler(sampler)");
326         return;
327      }
328   }
329
330   /* bind new sampler */
331   _mesa_bind_sampler(ctx, unit, sampObj);
332}
333
334void GLAPIENTRY
335_mesa_BindSampler_no_error(GLuint unit, GLuint sampler)
336{
337   GET_CURRENT_CONTEXT(ctx);
338   bind_sampler(ctx, unit, sampler, true);
339}
340
341void GLAPIENTRY
342_mesa_BindSampler(GLuint unit, GLuint sampler)
343{
344   GET_CURRENT_CONTEXT(ctx);
345
346   if (unit >= ctx->Const.MaxCombinedTextureImageUnits) {
347      _mesa_error(ctx, GL_INVALID_VALUE, "glBindSampler(unit %u)", unit);
348      return;
349   }
350
351   bind_sampler(ctx, unit, sampler, false);
352}
353
354
355static ALWAYS_INLINE void
356bind_samplers(struct gl_context *ctx, GLuint first, GLsizei count,
357              const GLuint *samplers, bool no_error)
358{
359   GLsizei i;
360
361   FLUSH_VERTICES(ctx, 0);
362
363   if (samplers) {
364      /* Note that the error semantics for multi-bind commands differ from
365       * those of other GL commands.
366       *
367       * The Issues section in the ARB_multi_bind spec says:
368       *
369       *    "(11) Typically, OpenGL specifies that if an error is generated by
370       *          a command, that command has no effect.  This is somewhat
371       *          unfortunate for multi-bind commands, because it would require
372       *          a first pass to scan the entire list of bound objects for
373       *          errors and then a second pass to actually perform the
374       *          bindings.  Should we have different error semantics?
375       *
376       *       RESOLVED:  Yes.  In this specification, when the parameters for
377       *       one of the <count> binding points are invalid, that binding
378       *       point is not updated and an error will be generated.  However,
379       *       other binding points in the same command will be updated if
380       *       their parameters are valid and no other error occurs."
381       */
382
383      _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
384
385      for (i = 0; i < count; i++) {
386         const GLuint unit = first + i;
387         struct gl_sampler_object * const currentSampler =
388             ctx->Texture.Unit[unit].Sampler;
389         struct gl_sampler_object *sampObj;
390
391         if (samplers[i] != 0) {
392            if (currentSampler && currentSampler->Name == samplers[i])
393               sampObj = currentSampler;
394            else
395               sampObj = lookup_samplerobj_locked(ctx, samplers[i]);
396
397            /* The ARB_multi_bind spec says:
398             *
399             *    "An INVALID_OPERATION error is generated if any value
400             *     in <samplers> is not zero or the name of an existing
401             *     sampler object (per binding)."
402             */
403            if (!no_error && !sampObj) {
404               _mesa_error(ctx, GL_INVALID_OPERATION,
405                           "glBindSamplers(samplers[%d]=%u is not zero or "
406                           "the name of an existing sampler object)",
407                           i, samplers[i]);
408               continue;
409            }
410         } else {
411            sampObj = NULL;
412         }
413
414         /* Bind the new sampler */
415         if (sampObj != currentSampler) {
416            _mesa_reference_sampler_object(ctx,
417                                           &ctx->Texture.Unit[unit].Sampler,
418                                           sampObj);
419            ctx->NewState |= _NEW_TEXTURE_OBJECT;
420         }
421      }
422
423      _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
424   } else {
425      /* Unbind all samplers in the range <first> through <first>+<count>-1 */
426      for (i = 0; i < count; i++) {
427         const GLuint unit = first + i;
428
429         if (ctx->Texture.Unit[unit].Sampler) {
430            _mesa_reference_sampler_object(ctx,
431                                           &ctx->Texture.Unit[unit].Sampler,
432                                           NULL);
433            ctx->NewState |= _NEW_TEXTURE_OBJECT;
434         }
435      }
436   }
437}
438
439
440void GLAPIENTRY
441_mesa_BindSamplers_no_error(GLuint first, GLsizei count, const GLuint *samplers)
442{
443   GET_CURRENT_CONTEXT(ctx);
444   bind_samplers(ctx, first, count, samplers, true);
445}
446
447
448void GLAPIENTRY
449_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers)
450{
451   GET_CURRENT_CONTEXT(ctx);
452
453   /* The ARB_multi_bind spec says:
454    *
455    *   "An INVALID_OPERATION error is generated if <first> + <count> is
456    *    greater than the number of texture image units supported by
457    *    the implementation."
458    */
459   if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
460      _mesa_error(ctx, GL_INVALID_OPERATION,
461                  "glBindSamplers(first=%u + count=%d > the value of "
462                  "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
463                  first, count, ctx->Const.MaxCombinedTextureImageUnits);
464      return;
465   }
466
467   bind_samplers(ctx, first, count, samplers, false);
468}
469
470
471/**
472 * Check if a coordinate wrap mode is legal.
473 * \return GL_TRUE if legal, GL_FALSE otherwise
474 */
475static GLboolean
476validate_texture_wrap_mode(struct gl_context *ctx, GLenum wrap)
477{
478   const struct gl_extensions * const e = &ctx->Extensions;
479
480   switch (wrap) {
481   case GL_CLAMP:
482   case GL_CLAMP_TO_EDGE:
483   case GL_REPEAT:
484   case GL_MIRRORED_REPEAT:
485      return GL_TRUE;
486   case GL_CLAMP_TO_BORDER:
487      return e->ARB_texture_border_clamp;
488   case GL_MIRROR_CLAMP_EXT:
489      return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp;
490   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
491      return e->ATI_texture_mirror_once || e->EXT_texture_mirror_clamp || e->ARB_texture_mirror_clamp_to_edge;
492   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
493      return e->EXT_texture_mirror_clamp;
494   default:
495      return GL_FALSE;
496   }
497}
498
499
500/**
501 * This is called just prior to changing any sampler object state.
502 */
503static inline void
504flush(struct gl_context *ctx)
505{
506   FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT);
507}
508
509void
510_mesa_set_sampler_wrap(struct gl_context *ctx, struct gl_sampler_object *samp,
511                       GLenum s, GLenum t, GLenum r)
512{
513   assert(validate_texture_wrap_mode(ctx, s));
514   assert(validate_texture_wrap_mode(ctx, t));
515   assert(validate_texture_wrap_mode(ctx, r));
516
517   if (samp->WrapS == s && samp->WrapT == t && samp->WrapR == r)
518      return;
519
520   flush(ctx);
521   samp->WrapS = s;
522   samp->WrapT = t;
523   samp->WrapR = r;
524}
525
526#define INVALID_PARAM 0x100
527#define INVALID_PNAME 0x101
528#define INVALID_VALUE 0x102
529
530static GLuint
531set_sampler_wrap_s(struct gl_context *ctx, struct gl_sampler_object *samp,
532                   GLint param)
533{
534   if (samp->WrapS == param)
535      return GL_FALSE;
536   if (validate_texture_wrap_mode(ctx, param)) {
537      flush(ctx);
538      samp->WrapS = param;
539      return GL_TRUE;
540   }
541   return INVALID_PARAM;
542}
543
544
545static GLuint
546set_sampler_wrap_t(struct gl_context *ctx, struct gl_sampler_object *samp,
547                   GLint param)
548{
549   if (samp->WrapT == param)
550      return GL_FALSE;
551   if (validate_texture_wrap_mode(ctx, param)) {
552      flush(ctx);
553      samp->WrapT = param;
554      return GL_TRUE;
555   }
556   return INVALID_PARAM;
557}
558
559
560static GLuint
561set_sampler_wrap_r(struct gl_context *ctx, struct gl_sampler_object *samp,
562                   GLint param)
563{
564   if (samp->WrapR == param)
565      return GL_FALSE;
566   if (validate_texture_wrap_mode(ctx, param)) {
567      flush(ctx);
568      samp->WrapR = param;
569      return GL_TRUE;
570   }
571   return INVALID_PARAM;
572}
573
574void
575_mesa_set_sampler_filters(struct gl_context *ctx,
576                          struct gl_sampler_object *samp,
577                          GLenum min_filter, GLenum mag_filter)
578{
579   assert(min_filter == GL_NEAREST ||
580          min_filter == GL_LINEAR ||
581          min_filter == GL_NEAREST_MIPMAP_NEAREST ||
582          min_filter == GL_LINEAR_MIPMAP_NEAREST ||
583          min_filter == GL_NEAREST_MIPMAP_LINEAR ||
584          min_filter == GL_LINEAR_MIPMAP_LINEAR);
585   assert(mag_filter == GL_NEAREST ||
586          mag_filter == GL_LINEAR);
587
588   if (samp->MinFilter == min_filter && samp->MagFilter == mag_filter)
589      return;
590
591   flush(ctx);
592   samp->MinFilter = min_filter;
593   samp->MagFilter = mag_filter;
594}
595
596static GLuint
597set_sampler_min_filter(struct gl_context *ctx, struct gl_sampler_object *samp,
598                       GLint param)
599{
600   if (samp->MinFilter == param)
601      return GL_FALSE;
602
603   switch (param) {
604   case GL_NEAREST:
605   case GL_LINEAR:
606   case GL_NEAREST_MIPMAP_NEAREST:
607   case GL_LINEAR_MIPMAP_NEAREST:
608   case GL_NEAREST_MIPMAP_LINEAR:
609   case GL_LINEAR_MIPMAP_LINEAR:
610      flush(ctx);
611      samp->MinFilter = param;
612      return GL_TRUE;
613   default:
614      return INVALID_PARAM;
615   }
616}
617
618
619static GLuint
620set_sampler_mag_filter(struct gl_context *ctx, struct gl_sampler_object *samp,
621                       GLint param)
622{
623   if (samp->MagFilter == param)
624      return GL_FALSE;
625
626   switch (param) {
627   case GL_NEAREST:
628   case GL_LINEAR:
629      flush(ctx);
630      samp->MagFilter = param;
631      return GL_TRUE;
632   default:
633      return INVALID_PARAM;
634   }
635}
636
637
638static GLuint
639set_sampler_lod_bias(struct gl_context *ctx, struct gl_sampler_object *samp,
640                     GLfloat param)
641{
642   if (samp->LodBias == param)
643      return GL_FALSE;
644
645   flush(ctx);
646   samp->LodBias = param;
647   return GL_TRUE;
648}
649
650
651static GLuint
652set_sampler_border_colorf(struct gl_context *ctx,
653                          struct gl_sampler_object *samp,
654                          const GLfloat params[4])
655{
656   flush(ctx);
657   samp->BorderColor.f[RCOMP] = params[0];
658   samp->BorderColor.f[GCOMP] = params[1];
659   samp->BorderColor.f[BCOMP] = params[2];
660   samp->BorderColor.f[ACOMP] = params[3];
661   return GL_TRUE;
662}
663
664
665static GLuint
666set_sampler_border_colori(struct gl_context *ctx,
667                          struct gl_sampler_object *samp,
668                          const GLint params[4])
669{
670   flush(ctx);
671   samp->BorderColor.i[RCOMP] = params[0];
672   samp->BorderColor.i[GCOMP] = params[1];
673   samp->BorderColor.i[BCOMP] = params[2];
674   samp->BorderColor.i[ACOMP] = params[3];
675   return GL_TRUE;
676}
677
678
679static GLuint
680set_sampler_border_colorui(struct gl_context *ctx,
681                           struct gl_sampler_object *samp,
682                           const GLuint params[4])
683{
684   flush(ctx);
685   samp->BorderColor.ui[RCOMP] = params[0];
686   samp->BorderColor.ui[GCOMP] = params[1];
687   samp->BorderColor.ui[BCOMP] = params[2];
688   samp->BorderColor.ui[ACOMP] = params[3];
689   return GL_TRUE;
690}
691
692
693static GLuint
694set_sampler_min_lod(struct gl_context *ctx, struct gl_sampler_object *samp,
695                    GLfloat param)
696{
697   if (samp->MinLod == param)
698      return GL_FALSE;
699
700   flush(ctx);
701   samp->MinLod = param;
702   return GL_TRUE;
703}
704
705
706static GLuint
707set_sampler_max_lod(struct gl_context *ctx, struct gl_sampler_object *samp,
708                    GLfloat param)
709{
710   if (samp->MaxLod == param)
711      return GL_FALSE;
712
713   flush(ctx);
714   samp->MaxLod = param;
715   return GL_TRUE;
716}
717
718
719static GLuint
720set_sampler_compare_mode(struct gl_context *ctx,
721                         struct gl_sampler_object *samp, GLint param)
722{
723    /* If GL_ARB_shadow is not supported, don't report an error.  The
724     * sampler object extension spec isn't clear on this extension interaction.
725     * Silences errors with Wine on older GPUs such as R200.
726     */
727   if (!ctx->Extensions.ARB_shadow)
728      return GL_FALSE;
729
730   if (samp->CompareMode == param)
731      return GL_FALSE;
732
733   if (param == GL_NONE ||
734       param == GL_COMPARE_R_TO_TEXTURE_ARB) {
735      flush(ctx);
736      samp->CompareMode = param;
737      return GL_TRUE;
738   }
739
740   return INVALID_PARAM;
741}
742
743
744static GLuint
745set_sampler_compare_func(struct gl_context *ctx,
746                         struct gl_sampler_object *samp, GLint param)
747{
748    /* If GL_ARB_shadow is not supported, don't report an error.  The
749     * sampler object extension spec isn't clear on this extension interaction.
750     * Silences errors with Wine on older GPUs such as R200.
751     */
752   if (!ctx->Extensions.ARB_shadow)
753      return GL_FALSE;
754
755   if (samp->CompareFunc == param)
756      return GL_FALSE;
757
758   switch (param) {
759   case GL_LEQUAL:
760   case GL_GEQUAL:
761   case GL_EQUAL:
762   case GL_NOTEQUAL:
763   case GL_LESS:
764   case GL_GREATER:
765   case GL_ALWAYS:
766   case GL_NEVER:
767      flush(ctx);
768      samp->CompareFunc = param;
769      return GL_TRUE;
770   default:
771      return INVALID_PARAM;
772   }
773}
774
775
776static GLuint
777set_sampler_max_anisotropy(struct gl_context *ctx,
778                           struct gl_sampler_object *samp, GLfloat param)
779{
780   if (!ctx->Extensions.EXT_texture_filter_anisotropic)
781      return INVALID_PNAME;
782
783   if (samp->MaxAnisotropy == param)
784      return GL_FALSE;
785
786   if (param < 1.0F)
787      return INVALID_VALUE;
788
789   flush(ctx);
790   /* clamp to max, that's what NVIDIA does */
791   samp->MaxAnisotropy = MIN2(param, ctx->Const.MaxTextureMaxAnisotropy);
792   return GL_TRUE;
793}
794
795
796static GLuint
797set_sampler_cube_map_seamless(struct gl_context *ctx,
798                              struct gl_sampler_object *samp, GLboolean param)
799{
800   if (!_mesa_is_desktop_gl(ctx)
801       || !ctx->Extensions.AMD_seamless_cubemap_per_texture)
802      return INVALID_PNAME;
803
804   if (samp->CubeMapSeamless == param)
805      return GL_FALSE;
806
807   if (param != GL_TRUE && param != GL_FALSE)
808      return INVALID_VALUE;
809
810   flush(ctx);
811   samp->CubeMapSeamless = param;
812   return GL_TRUE;
813}
814
815void
816_mesa_set_sampler_srgb_decode(struct gl_context *ctx,
817                              struct gl_sampler_object *samp, GLenum param)
818{
819   assert(param == GL_DECODE_EXT || param == GL_SKIP_DECODE_EXT);
820
821   flush(ctx);
822   samp->sRGBDecode = param;
823}
824
825static GLuint
826set_sampler_srgb_decode(struct gl_context *ctx,
827                              struct gl_sampler_object *samp, GLenum param)
828{
829   if (!ctx->Extensions.EXT_texture_sRGB_decode)
830      return INVALID_PNAME;
831
832   if (samp->sRGBDecode == param)
833      return GL_FALSE;
834
835   /* The EXT_texture_sRGB_decode spec says:
836    *
837    *    "INVALID_ENUM is generated if the <pname> parameter of
838    *     TexParameter[i,f,Ii,Iui][v][EXT],
839    *     MultiTexParameter[i,f,Ii,Iui][v]EXT,
840    *     TextureParameter[i,f,Ii,Iui][v]EXT, SamplerParameter[i,f,Ii,Iui][v]
841    *     is TEXTURE_SRGB_DECODE_EXT when the <param> parameter is not one of
842    *     DECODE_EXT or SKIP_DECODE_EXT.
843    *
844    * Returning INVALID_PARAM makes that happen.
845    */
846   if (param != GL_DECODE_EXT && param != GL_SKIP_DECODE_EXT)
847      return INVALID_PARAM;
848
849   flush(ctx);
850   samp->sRGBDecode = param;
851   return GL_TRUE;
852}
853
854static struct gl_sampler_object *
855sampler_parameter_error_check(struct gl_context *ctx, GLuint sampler,
856                              bool get, const char *name)
857{
858   struct gl_sampler_object *sampObj;
859
860   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
861   if (!sampObj) {
862      /* OpenGL 4.5 spec, section "8.2 Sampler Objects", page 176 of the PDF
863       * states:
864       *
865       *    "An INVALID_OPERATION error is generated if sampler is not the name
866       *    of a sampler object previously returned from a call to
867       *    GenSamplers."
868       */
869      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid sampler)", name);
870      return NULL;
871   }
872
873   if (!get && sampObj->HandleAllocated) {
874      /* The ARB_bindless_texture spec says:
875       *
876       * "The error INVALID_OPERATION is generated by SamplerParameter* if
877       *  <sampler> identifies a sampler object referenced by one or more
878       *  texture handles."
879       */
880      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable sampler)", name);
881      return NULL;
882   }
883
884   return sampObj;
885}
886
887void GLAPIENTRY
888_mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
889{
890   struct gl_sampler_object *sampObj;
891   GLuint res;
892   GET_CURRENT_CONTEXT(ctx);
893
894   sampObj = sampler_parameter_error_check(ctx, sampler, false,
895                                           "glSamplerParameteri");
896   if (!sampObj)
897      return;
898
899   switch (pname) {
900   case GL_TEXTURE_WRAP_S:
901      res = set_sampler_wrap_s(ctx, sampObj, param);
902      break;
903   case GL_TEXTURE_WRAP_T:
904      res = set_sampler_wrap_t(ctx, sampObj, param);
905      break;
906   case GL_TEXTURE_WRAP_R:
907      res = set_sampler_wrap_r(ctx, sampObj, param);
908      break;
909   case GL_TEXTURE_MIN_FILTER:
910      res = set_sampler_min_filter(ctx, sampObj, param);
911      break;
912   case GL_TEXTURE_MAG_FILTER:
913      res = set_sampler_mag_filter(ctx, sampObj, param);
914      break;
915   case GL_TEXTURE_MIN_LOD:
916      res = set_sampler_min_lod(ctx, sampObj, (GLfloat) param);
917      break;
918   case GL_TEXTURE_MAX_LOD:
919      res = set_sampler_max_lod(ctx, sampObj, (GLfloat) param);
920      break;
921   case GL_TEXTURE_LOD_BIAS:
922      res = set_sampler_lod_bias(ctx, sampObj, (GLfloat) param);
923      break;
924   case GL_TEXTURE_COMPARE_MODE:
925      res = set_sampler_compare_mode(ctx, sampObj, param);
926      break;
927   case GL_TEXTURE_COMPARE_FUNC:
928      res = set_sampler_compare_func(ctx, sampObj, param);
929      break;
930   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
931      res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) param);
932      break;
933   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
934      res = set_sampler_cube_map_seamless(ctx, sampObj, param);
935      break;
936   case GL_TEXTURE_SRGB_DECODE_EXT:
937      res = set_sampler_srgb_decode(ctx, sampObj, param);
938      break;
939   case GL_TEXTURE_BORDER_COLOR:
940      /* fall-through */
941   default:
942      res = INVALID_PNAME;
943   }
944
945   switch (res) {
946   case GL_FALSE:
947      /* no change */
948      break;
949   case GL_TRUE:
950      /* state change - we do nothing special at this time */
951      break;
952   case INVALID_PNAME:
953      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteri(pname=%s)\n",
954                  _mesa_enum_to_string(pname));
955      break;
956   case INVALID_PARAM:
957      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteri(param=%d)\n",
958                  param);
959      break;
960   case INVALID_VALUE:
961      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameteri(param=%d)\n",
962                  param);
963      break;
964   default:
965      ;
966   }
967}
968
969
970void GLAPIENTRY
971_mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
972{
973   struct gl_sampler_object *sampObj;
974   GLuint res;
975   GET_CURRENT_CONTEXT(ctx);
976
977   sampObj = sampler_parameter_error_check(ctx, sampler, false,
978                                           "glSamplerParameterf");
979   if (!sampObj)
980      return;
981
982   switch (pname) {
983   case GL_TEXTURE_WRAP_S:
984      res = set_sampler_wrap_s(ctx, sampObj, (GLint) param);
985      break;
986   case GL_TEXTURE_WRAP_T:
987      res = set_sampler_wrap_t(ctx, sampObj, (GLint) param);
988      break;
989   case GL_TEXTURE_WRAP_R:
990      res = set_sampler_wrap_r(ctx, sampObj, (GLint) param);
991      break;
992   case GL_TEXTURE_MIN_FILTER:
993      res = set_sampler_min_filter(ctx, sampObj, (GLint) param);
994      break;
995   case GL_TEXTURE_MAG_FILTER:
996      res = set_sampler_mag_filter(ctx, sampObj, (GLint) param);
997      break;
998   case GL_TEXTURE_MIN_LOD:
999      res = set_sampler_min_lod(ctx, sampObj, param);
1000      break;
1001   case GL_TEXTURE_MAX_LOD:
1002      res = set_sampler_max_lod(ctx, sampObj, param);
1003      break;
1004   case GL_TEXTURE_LOD_BIAS:
1005      res = set_sampler_lod_bias(ctx, sampObj, param);
1006      break;
1007   case GL_TEXTURE_COMPARE_MODE:
1008      res = set_sampler_compare_mode(ctx, sampObj, (GLint) param);
1009      break;
1010   case GL_TEXTURE_COMPARE_FUNC:
1011      res = set_sampler_compare_func(ctx, sampObj, (GLint) param);
1012      break;
1013   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1014      res = set_sampler_max_anisotropy(ctx, sampObj, param);
1015      break;
1016   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1017      res = set_sampler_cube_map_seamless(ctx, sampObj, (GLboolean) param);
1018      break;
1019   case GL_TEXTURE_SRGB_DECODE_EXT:
1020      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) param);
1021      break;
1022   case GL_TEXTURE_BORDER_COLOR:
1023      /* fall-through */
1024   default:
1025      res = INVALID_PNAME;
1026   }
1027
1028   switch (res) {
1029   case GL_FALSE:
1030      /* no change */
1031      break;
1032   case GL_TRUE:
1033      /* state change - we do nothing special at this time */
1034      break;
1035   case INVALID_PNAME:
1036      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterf(pname=%s)\n",
1037                  _mesa_enum_to_string(pname));
1038      break;
1039   case INVALID_PARAM:
1040      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterf(param=%f)\n",
1041                  param);
1042      break;
1043   case INVALID_VALUE:
1044      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterf(param=%f)\n",
1045                  param);
1046      break;
1047   default:
1048      ;
1049   }
1050}
1051
1052void GLAPIENTRY
1053_mesa_SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *params)
1054{
1055   struct gl_sampler_object *sampObj;
1056   GLuint res;
1057   GET_CURRENT_CONTEXT(ctx);
1058
1059   sampObj = sampler_parameter_error_check(ctx, sampler, false,
1060                                           "glSamplerParameteriv");
1061   if (!sampObj)
1062      return;
1063
1064   switch (pname) {
1065   case GL_TEXTURE_WRAP_S:
1066      res = set_sampler_wrap_s(ctx, sampObj, params[0]);
1067      break;
1068   case GL_TEXTURE_WRAP_T:
1069      res = set_sampler_wrap_t(ctx, sampObj, params[0]);
1070      break;
1071   case GL_TEXTURE_WRAP_R:
1072      res = set_sampler_wrap_r(ctx, sampObj, params[0]);
1073      break;
1074   case GL_TEXTURE_MIN_FILTER:
1075      res = set_sampler_min_filter(ctx, sampObj, params[0]);
1076      break;
1077   case GL_TEXTURE_MAG_FILTER:
1078      res = set_sampler_mag_filter(ctx, sampObj, params[0]);
1079      break;
1080   case GL_TEXTURE_MIN_LOD:
1081      res = set_sampler_min_lod(ctx, sampObj, (GLfloat) params[0]);
1082      break;
1083   case GL_TEXTURE_MAX_LOD:
1084      res = set_sampler_max_lod(ctx, sampObj, (GLfloat) params[0]);
1085      break;
1086   case GL_TEXTURE_LOD_BIAS:
1087      res = set_sampler_lod_bias(ctx, sampObj, (GLfloat) params[0]);
1088      break;
1089   case GL_TEXTURE_COMPARE_MODE:
1090      res = set_sampler_compare_mode(ctx, sampObj, params[0]);
1091      break;
1092   case GL_TEXTURE_COMPARE_FUNC:
1093      res = set_sampler_compare_func(ctx, sampObj, params[0]);
1094      break;
1095   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1096      res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) params[0]);
1097      break;
1098   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1099      res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
1100      break;
1101   case GL_TEXTURE_SRGB_DECODE_EXT:
1102      res = set_sampler_srgb_decode(ctx, sampObj, params[0]);
1103      break;
1104   case GL_TEXTURE_BORDER_COLOR:
1105      {
1106         GLfloat c[4];
1107         c[0] = INT_TO_FLOAT(params[0]);
1108         c[1] = INT_TO_FLOAT(params[1]);
1109         c[2] = INT_TO_FLOAT(params[2]);
1110         c[3] = INT_TO_FLOAT(params[3]);
1111         res = set_sampler_border_colorf(ctx, sampObj, c);
1112      }
1113      break;
1114   default:
1115      res = INVALID_PNAME;
1116   }
1117
1118   switch (res) {
1119   case GL_FALSE:
1120      /* no change */
1121      break;
1122   case GL_TRUE:
1123      /* state change - we do nothing special at this time */
1124      break;
1125   case INVALID_PNAME:
1126      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteriv(pname=%s)\n",
1127                  _mesa_enum_to_string(pname));
1128      break;
1129   case INVALID_PARAM:
1130      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameteriv(param=%d)\n",
1131                  params[0]);
1132      break;
1133   case INVALID_VALUE:
1134      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameteriv(param=%d)\n",
1135                  params[0]);
1136      break;
1137   default:
1138      ;
1139   }
1140}
1141
1142void GLAPIENTRY
1143_mesa_SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *params)
1144{
1145   struct gl_sampler_object *sampObj;
1146   GLuint res;
1147   GET_CURRENT_CONTEXT(ctx);
1148
1149   sampObj = sampler_parameter_error_check(ctx, sampler, false,
1150                                           "glSamplerParameterfv");
1151   if (!sampObj)
1152      return;
1153
1154   switch (pname) {
1155   case GL_TEXTURE_WRAP_S:
1156      res = set_sampler_wrap_s(ctx, sampObj, (GLint) params[0]);
1157      break;
1158   case GL_TEXTURE_WRAP_T:
1159      res = set_sampler_wrap_t(ctx, sampObj, (GLint) params[0]);
1160      break;
1161   case GL_TEXTURE_WRAP_R:
1162      res = set_sampler_wrap_r(ctx, sampObj, (GLint) params[0]);
1163      break;
1164   case GL_TEXTURE_MIN_FILTER:
1165      res = set_sampler_min_filter(ctx, sampObj, (GLint) params[0]);
1166      break;
1167   case GL_TEXTURE_MAG_FILTER:
1168      res = set_sampler_mag_filter(ctx, sampObj, (GLint) params[0]);
1169      break;
1170   case GL_TEXTURE_MIN_LOD:
1171      res = set_sampler_min_lod(ctx, sampObj, params[0]);
1172      break;
1173   case GL_TEXTURE_MAX_LOD:
1174      res = set_sampler_max_lod(ctx, sampObj, params[0]);
1175      break;
1176   case GL_TEXTURE_LOD_BIAS:
1177      res = set_sampler_lod_bias(ctx, sampObj, params[0]);
1178      break;
1179   case GL_TEXTURE_COMPARE_MODE:
1180      res = set_sampler_compare_mode(ctx, sampObj, (GLint) params[0]);
1181      break;
1182   case GL_TEXTURE_COMPARE_FUNC:
1183      res = set_sampler_compare_func(ctx, sampObj, (GLint) params[0]);
1184      break;
1185   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1186      res = set_sampler_max_anisotropy(ctx, sampObj, params[0]);
1187      break;
1188   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1189      res = set_sampler_cube_map_seamless(ctx, sampObj, (GLboolean) params[0]);
1190      break;
1191   case GL_TEXTURE_SRGB_DECODE_EXT:
1192      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
1193      break;
1194   case GL_TEXTURE_BORDER_COLOR:
1195      res = set_sampler_border_colorf(ctx, sampObj, params);
1196      break;
1197   default:
1198      res = INVALID_PNAME;
1199   }
1200
1201   switch (res) {
1202   case GL_FALSE:
1203      /* no change */
1204      break;
1205   case GL_TRUE:
1206      /* state change - we do nothing special at this time */
1207      break;
1208   case INVALID_PNAME:
1209      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterfv(pname=%s)\n",
1210                  _mesa_enum_to_string(pname));
1211      break;
1212   case INVALID_PARAM:
1213      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterfv(param=%f)\n",
1214                  params[0]);
1215      break;
1216   case INVALID_VALUE:
1217      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterfv(param=%f)\n",
1218                  params[0]);
1219      break;
1220   default:
1221      ;
1222   }
1223}
1224
1225void GLAPIENTRY
1226_mesa_SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint *params)
1227{
1228   struct gl_sampler_object *sampObj;
1229   GLuint res;
1230   GET_CURRENT_CONTEXT(ctx);
1231
1232   sampObj = sampler_parameter_error_check(ctx, sampler, false,
1233                                           "glSamplerParameterIiv");
1234   if (!sampObj)
1235      return;
1236
1237   switch (pname) {
1238   case GL_TEXTURE_WRAP_S:
1239      res = set_sampler_wrap_s(ctx, sampObj, params[0]);
1240      break;
1241   case GL_TEXTURE_WRAP_T:
1242      res = set_sampler_wrap_t(ctx, sampObj, params[0]);
1243      break;
1244   case GL_TEXTURE_WRAP_R:
1245      res = set_sampler_wrap_r(ctx, sampObj, params[0]);
1246      break;
1247   case GL_TEXTURE_MIN_FILTER:
1248      res = set_sampler_min_filter(ctx, sampObj, params[0]);
1249      break;
1250   case GL_TEXTURE_MAG_FILTER:
1251      res = set_sampler_mag_filter(ctx, sampObj, params[0]);
1252      break;
1253   case GL_TEXTURE_MIN_LOD:
1254      res = set_sampler_min_lod(ctx, sampObj, (GLfloat) params[0]);
1255      break;
1256   case GL_TEXTURE_MAX_LOD:
1257      res = set_sampler_max_lod(ctx, sampObj, (GLfloat) params[0]);
1258      break;
1259   case GL_TEXTURE_LOD_BIAS:
1260      res = set_sampler_lod_bias(ctx, sampObj, (GLfloat) params[0]);
1261      break;
1262   case GL_TEXTURE_COMPARE_MODE:
1263      res = set_sampler_compare_mode(ctx, sampObj, params[0]);
1264      break;
1265   case GL_TEXTURE_COMPARE_FUNC:
1266      res = set_sampler_compare_func(ctx, sampObj, params[0]);
1267      break;
1268   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1269      res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) params[0]);
1270      break;
1271   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1272      res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
1273      break;
1274   case GL_TEXTURE_SRGB_DECODE_EXT:
1275      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
1276      break;
1277   case GL_TEXTURE_BORDER_COLOR:
1278      res = set_sampler_border_colori(ctx, sampObj, params);
1279      break;
1280   default:
1281      res = INVALID_PNAME;
1282   }
1283
1284   switch (res) {
1285   case GL_FALSE:
1286      /* no change */
1287      break;
1288   case GL_TRUE:
1289      /* state change - we do nothing special at this time */
1290      break;
1291   case INVALID_PNAME:
1292      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIiv(pname=%s)\n",
1293                  _mesa_enum_to_string(pname));
1294      break;
1295   case INVALID_PARAM:
1296      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIiv(param=%d)\n",
1297                  params[0]);
1298      break;
1299   case INVALID_VALUE:
1300      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterIiv(param=%d)\n",
1301                  params[0]);
1302      break;
1303   default:
1304      ;
1305   }
1306}
1307
1308
1309void GLAPIENTRY
1310_mesa_SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint *params)
1311{
1312   struct gl_sampler_object *sampObj;
1313   GLuint res;
1314   GET_CURRENT_CONTEXT(ctx);
1315
1316   sampObj = sampler_parameter_error_check(ctx, sampler, false,
1317                                           "glSamplerParameterIuiv");
1318   if (!sampObj)
1319      return;
1320
1321   switch (pname) {
1322   case GL_TEXTURE_WRAP_S:
1323      res = set_sampler_wrap_s(ctx, sampObj, params[0]);
1324      break;
1325   case GL_TEXTURE_WRAP_T:
1326      res = set_sampler_wrap_t(ctx, sampObj, params[0]);
1327      break;
1328   case GL_TEXTURE_WRAP_R:
1329      res = set_sampler_wrap_r(ctx, sampObj, params[0]);
1330      break;
1331   case GL_TEXTURE_MIN_FILTER:
1332      res = set_sampler_min_filter(ctx, sampObj, params[0]);
1333      break;
1334   case GL_TEXTURE_MAG_FILTER:
1335      res = set_sampler_mag_filter(ctx, sampObj, params[0]);
1336      break;
1337   case GL_TEXTURE_MIN_LOD:
1338      res = set_sampler_min_lod(ctx, sampObj, (GLfloat) params[0]);
1339      break;
1340   case GL_TEXTURE_MAX_LOD:
1341      res = set_sampler_max_lod(ctx, sampObj, (GLfloat) params[0]);
1342      break;
1343   case GL_TEXTURE_LOD_BIAS:
1344      res = set_sampler_lod_bias(ctx, sampObj, (GLfloat) params[0]);
1345      break;
1346   case GL_TEXTURE_COMPARE_MODE:
1347      res = set_sampler_compare_mode(ctx, sampObj, params[0]);
1348      break;
1349   case GL_TEXTURE_COMPARE_FUNC:
1350      res = set_sampler_compare_func(ctx, sampObj, params[0]);
1351      break;
1352   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1353      res = set_sampler_max_anisotropy(ctx, sampObj, (GLfloat) params[0]);
1354      break;
1355   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1356      res = set_sampler_cube_map_seamless(ctx, sampObj, params[0]);
1357      break;
1358   case GL_TEXTURE_SRGB_DECODE_EXT:
1359      res = set_sampler_srgb_decode(ctx, sampObj, (GLenum) params[0]);
1360      break;
1361   case GL_TEXTURE_BORDER_COLOR:
1362      res = set_sampler_border_colorui(ctx, sampObj, params);
1363      break;
1364   default:
1365      res = INVALID_PNAME;
1366   }
1367
1368   switch (res) {
1369   case GL_FALSE:
1370      /* no change */
1371      break;
1372   case GL_TRUE:
1373      /* state change - we do nothing special at this time */
1374      break;
1375   case INVALID_PNAME:
1376      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIuiv(pname=%s)\n",
1377                  _mesa_enum_to_string(pname));
1378      break;
1379   case INVALID_PARAM:
1380      _mesa_error(ctx, GL_INVALID_ENUM, "glSamplerParameterIuiv(param=%u)\n",
1381                  params[0]);
1382      break;
1383   case INVALID_VALUE:
1384      _mesa_error(ctx, GL_INVALID_VALUE, "glSamplerParameterIuiv(param=%u)\n",
1385                  params[0]);
1386      break;
1387   default:
1388      ;
1389   }
1390}
1391
1392
1393void GLAPIENTRY
1394_mesa_GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
1395{
1396   struct gl_sampler_object *sampObj;
1397   GET_CURRENT_CONTEXT(ctx);
1398
1399   sampObj = sampler_parameter_error_check(ctx, sampler, true,
1400                                           "glGetSamplerParameteriv");
1401   if (!sampObj)
1402      return;
1403
1404   switch (pname) {
1405   case GL_TEXTURE_WRAP_S:
1406      *params = sampObj->WrapS;
1407      break;
1408   case GL_TEXTURE_WRAP_T:
1409      *params = sampObj->WrapT;
1410      break;
1411   case GL_TEXTURE_WRAP_R:
1412      *params = sampObj->WrapR;
1413      break;
1414   case GL_TEXTURE_MIN_FILTER:
1415      *params = sampObj->MinFilter;
1416      break;
1417   case GL_TEXTURE_MAG_FILTER:
1418      *params = sampObj->MagFilter;
1419      break;
1420   case GL_TEXTURE_MIN_LOD:
1421      /* GL spec 'Data Conversions' section specifies that floating-point
1422       * value in integer Get function is rounded to nearest integer
1423       */
1424      *params = IROUND(sampObj->MinLod);
1425      break;
1426   case GL_TEXTURE_MAX_LOD:
1427      /* GL spec 'Data Conversions' section specifies that floating-point
1428       * value in integer Get function is rounded to nearest integer
1429       */
1430      *params = IROUND(sampObj->MaxLod);
1431      break;
1432   case GL_TEXTURE_LOD_BIAS:
1433      /* GL spec 'Data Conversions' section specifies that floating-point
1434       * value in integer Get function is rounded to nearest integer
1435       */
1436      *params = IROUND(sampObj->LodBias);
1437      break;
1438   case GL_TEXTURE_COMPARE_MODE:
1439      *params = sampObj->CompareMode;
1440      break;
1441   case GL_TEXTURE_COMPARE_FUNC:
1442      *params = sampObj->CompareFunc;
1443      break;
1444   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1445      /* GL spec 'Data Conversions' section specifies that floating-point
1446       * value in integer Get function is rounded to nearest integer
1447       */
1448      *params = IROUND(sampObj->MaxAnisotropy);
1449      break;
1450   case GL_TEXTURE_BORDER_COLOR:
1451      params[0] = FLOAT_TO_INT(sampObj->BorderColor.f[0]);
1452      params[1] = FLOAT_TO_INT(sampObj->BorderColor.f[1]);
1453      params[2] = FLOAT_TO_INT(sampObj->BorderColor.f[2]);
1454      params[3] = FLOAT_TO_INT(sampObj->BorderColor.f[3]);
1455      break;
1456   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1457      if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
1458         goto invalid_pname;
1459      *params = sampObj->CubeMapSeamless;
1460      break;
1461   case GL_TEXTURE_SRGB_DECODE_EXT:
1462      if (!ctx->Extensions.EXT_texture_sRGB_decode)
1463         goto invalid_pname;
1464      *params = (GLenum) sampObj->sRGBDecode;
1465      break;
1466   default:
1467      goto invalid_pname;
1468   }
1469   return;
1470
1471invalid_pname:
1472   _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameteriv(pname=%s)",
1473               _mesa_enum_to_string(pname));
1474}
1475
1476
1477void GLAPIENTRY
1478_mesa_GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
1479{
1480   struct gl_sampler_object *sampObj;
1481   GET_CURRENT_CONTEXT(ctx);
1482
1483   sampObj = sampler_parameter_error_check(ctx, sampler, true,
1484                                           "glGetSamplerParameterfv");
1485   if (!sampObj)
1486      return;
1487
1488   switch (pname) {
1489   case GL_TEXTURE_WRAP_S:
1490      *params = (GLfloat) sampObj->WrapS;
1491      break;
1492   case GL_TEXTURE_WRAP_T:
1493      *params = (GLfloat) sampObj->WrapT;
1494      break;
1495   case GL_TEXTURE_WRAP_R:
1496      *params = (GLfloat) sampObj->WrapR;
1497      break;
1498   case GL_TEXTURE_MIN_FILTER:
1499      *params = (GLfloat) sampObj->MinFilter;
1500      break;
1501   case GL_TEXTURE_MAG_FILTER:
1502      *params = (GLfloat) sampObj->MagFilter;
1503      break;
1504   case GL_TEXTURE_MIN_LOD:
1505      *params = sampObj->MinLod;
1506      break;
1507   case GL_TEXTURE_MAX_LOD:
1508      *params = sampObj->MaxLod;
1509      break;
1510   case GL_TEXTURE_LOD_BIAS:
1511      *params = sampObj->LodBias;
1512      break;
1513   case GL_TEXTURE_COMPARE_MODE:
1514      *params = (GLfloat) sampObj->CompareMode;
1515      break;
1516   case GL_TEXTURE_COMPARE_FUNC:
1517      *params = (GLfloat) sampObj->CompareFunc;
1518      break;
1519   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1520      *params = sampObj->MaxAnisotropy;
1521      break;
1522   case GL_TEXTURE_BORDER_COLOR:
1523      params[0] = sampObj->BorderColor.f[0];
1524      params[1] = sampObj->BorderColor.f[1];
1525      params[2] = sampObj->BorderColor.f[2];
1526      params[3] = sampObj->BorderColor.f[3];
1527      break;
1528   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1529      if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
1530         goto invalid_pname;
1531      *params = (GLfloat) sampObj->CubeMapSeamless;
1532      break;
1533   case GL_TEXTURE_SRGB_DECODE_EXT:
1534      if (!ctx->Extensions.EXT_texture_sRGB_decode)
1535         goto invalid_pname;
1536      *params = (GLfloat) sampObj->sRGBDecode;
1537      break;
1538   default:
1539      goto invalid_pname;
1540   }
1541   return;
1542
1543invalid_pname:
1544   _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterfv(pname=%s)",
1545               _mesa_enum_to_string(pname));
1546}
1547
1548
1549void GLAPIENTRY
1550_mesa_GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint *params)
1551{
1552   struct gl_sampler_object *sampObj;
1553   GET_CURRENT_CONTEXT(ctx);
1554
1555   sampObj = sampler_parameter_error_check(ctx, sampler, true,
1556                                           "glGetSamplerParameterIiv");
1557   if (!sampObj)
1558      return;
1559
1560   switch (pname) {
1561   case GL_TEXTURE_WRAP_S:
1562      *params = sampObj->WrapS;
1563      break;
1564   case GL_TEXTURE_WRAP_T:
1565      *params = sampObj->WrapT;
1566      break;
1567   case GL_TEXTURE_WRAP_R:
1568      *params = sampObj->WrapR;
1569      break;
1570   case GL_TEXTURE_MIN_FILTER:
1571      *params = sampObj->MinFilter;
1572      break;
1573   case GL_TEXTURE_MAG_FILTER:
1574      *params = sampObj->MagFilter;
1575      break;
1576   case GL_TEXTURE_MIN_LOD:
1577      *params = (GLint) sampObj->MinLod;
1578      break;
1579   case GL_TEXTURE_MAX_LOD:
1580      *params = (GLint) sampObj->MaxLod;
1581      break;
1582   case GL_TEXTURE_LOD_BIAS:
1583      *params = (GLint) sampObj->LodBias;
1584      break;
1585   case GL_TEXTURE_COMPARE_MODE:
1586      *params = sampObj->CompareMode;
1587      break;
1588   case GL_TEXTURE_COMPARE_FUNC:
1589      *params = sampObj->CompareFunc;
1590      break;
1591   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1592      *params = (GLint) sampObj->MaxAnisotropy;
1593      break;
1594   case GL_TEXTURE_BORDER_COLOR:
1595      params[0] = sampObj->BorderColor.i[0];
1596      params[1] = sampObj->BorderColor.i[1];
1597      params[2] = sampObj->BorderColor.i[2];
1598      params[3] = sampObj->BorderColor.i[3];
1599      break;
1600   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1601      if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
1602         goto invalid_pname;
1603      *params = sampObj->CubeMapSeamless;
1604      break;
1605   case GL_TEXTURE_SRGB_DECODE_EXT:
1606      if (!ctx->Extensions.EXT_texture_sRGB_decode)
1607         goto invalid_pname;
1608      *params = (GLenum) sampObj->sRGBDecode;
1609      break;
1610   default:
1611      goto invalid_pname;
1612   }
1613   return;
1614
1615invalid_pname:
1616   _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterIiv(pname=%s)",
1617               _mesa_enum_to_string(pname));
1618}
1619
1620
1621void GLAPIENTRY
1622_mesa_GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint *params)
1623{
1624   struct gl_sampler_object *sampObj;
1625   GET_CURRENT_CONTEXT(ctx);
1626
1627   sampObj = sampler_parameter_error_check(ctx, sampler, true,
1628                                           "glGetSamplerParameterIuiv");
1629   if (!sampObj)
1630      return;
1631
1632   switch (pname) {
1633   case GL_TEXTURE_WRAP_S:
1634      *params = sampObj->WrapS;
1635      break;
1636   case GL_TEXTURE_WRAP_T:
1637      *params = sampObj->WrapT;
1638      break;
1639   case GL_TEXTURE_WRAP_R:
1640      *params = sampObj->WrapR;
1641      break;
1642   case GL_TEXTURE_MIN_FILTER:
1643      *params = sampObj->MinFilter;
1644      break;
1645   case GL_TEXTURE_MAG_FILTER:
1646      *params = sampObj->MagFilter;
1647      break;
1648   case GL_TEXTURE_MIN_LOD:
1649      *params = (GLuint) sampObj->MinLod;
1650      break;
1651   case GL_TEXTURE_MAX_LOD:
1652      *params = (GLuint) sampObj->MaxLod;
1653      break;
1654   case GL_TEXTURE_LOD_BIAS:
1655      *params = (GLuint) sampObj->LodBias;
1656      break;
1657   case GL_TEXTURE_COMPARE_MODE:
1658      *params = sampObj->CompareMode;
1659      break;
1660   case GL_TEXTURE_COMPARE_FUNC:
1661      *params = sampObj->CompareFunc;
1662      break;
1663   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1664      *params = (GLuint) sampObj->MaxAnisotropy;
1665      break;
1666   case GL_TEXTURE_BORDER_COLOR:
1667      params[0] = sampObj->BorderColor.ui[0];
1668      params[1] = sampObj->BorderColor.ui[1];
1669      params[2] = sampObj->BorderColor.ui[2];
1670      params[3] = sampObj->BorderColor.ui[3];
1671      break;
1672   case GL_TEXTURE_CUBE_MAP_SEAMLESS:
1673      if (!ctx->Extensions.AMD_seamless_cubemap_per_texture)
1674         goto invalid_pname;
1675      *params = sampObj->CubeMapSeamless;
1676      break;
1677   case GL_TEXTURE_SRGB_DECODE_EXT:
1678      if (!ctx->Extensions.EXT_texture_sRGB_decode)
1679         goto invalid_pname;
1680      *params = (GLenum) sampObj->sRGBDecode;
1681      break;
1682   default:
1683      goto invalid_pname;
1684   }
1685   return;
1686
1687invalid_pname:
1688   _mesa_error(ctx, GL_INVALID_ENUM, "glGetSamplerParameterIuiv(pname=%s)",
1689               _mesa_enum_to_string(pname));
1690}
1691
1692
1693void
1694_mesa_init_sampler_object_functions(struct dd_function_table *driver)
1695{
1696   driver->NewSamplerObject = _mesa_new_sampler_object;
1697}
1698