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