viewport.c revision 7ec681f3
1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2009  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 viewport.c
28 * glViewport and glDepthRange functions.
29 */
30
31
32#include "context.h"
33#include "enums.h"
34#include "macros.h"
35#include "mtypes.h"
36#include "viewport.h"
37
38static void
39clamp_viewport(struct gl_context *ctx, GLfloat *x, GLfloat *y,
40               GLfloat *width, GLfloat *height)
41{
42   /* clamp width and height to the implementation dependent range */
43   *width  = MIN2(*width, (GLfloat) ctx->Const.MaxViewportWidth);
44   *height = MIN2(*height, (GLfloat) ctx->Const.MaxViewportHeight);
45
46   /* The GL_ARB_viewport_array spec says:
47    *
48    *     "The location of the viewport's bottom-left corner, given by (x,y),
49    *     are clamped to be within the implementation-dependent viewport
50    *     bounds range.  The viewport bounds range [min, max] tuple may be
51    *     determined by calling GetFloatv with the symbolic constant
52    *     VIEWPORT_BOUNDS_RANGE (see section 6.1)."
53    */
54   if (_mesa_has_ARB_viewport_array(ctx) ||
55       _mesa_has_OES_viewport_array(ctx)) {
56      *x = CLAMP(*x,
57                 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
58      *y = CLAMP(*y,
59                 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
60   }
61}
62
63static void
64set_viewport_no_notify(struct gl_context *ctx, unsigned idx,
65                       GLfloat x, GLfloat y,
66                       GLfloat width, GLfloat height)
67{
68   if (ctx->ViewportArray[idx].X == x &&
69       ctx->ViewportArray[idx].Width == width &&
70       ctx->ViewportArray[idx].Y == y &&
71       ctx->ViewportArray[idx].Height == height)
72      return;
73
74   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewViewport ? 0 : _NEW_VIEWPORT,
75                  GL_VIEWPORT_BIT);
76   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
77
78   ctx->ViewportArray[idx].X = x;
79   ctx->ViewportArray[idx].Width = width;
80   ctx->ViewportArray[idx].Y = y;
81   ctx->ViewportArray[idx].Height = height;
82}
83
84struct gl_viewport_inputs {
85   GLfloat X, Y;                /**< position */
86   GLfloat Width, Height;       /**< size */
87};
88
89struct gl_depthrange_inputs {
90   GLdouble Near, Far;          /**< Depth buffer range */
91};
92
93static void
94viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei width,
95         GLsizei height)
96{
97   struct gl_viewport_inputs input = { x, y, width, height };
98
99   /* Clamp the viewport to the implementation dependent values. */
100   clamp_viewport(ctx, &input.X, &input.Y, &input.Width, &input.Height);
101
102   /* The GL_ARB_viewport_array spec says:
103    *
104    *     "Viewport sets the parameters for all viewports to the same values
105    *     and is equivalent (assuming no errors are generated) to:
106    *
107    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
108    *         ViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);"
109    *
110    * Set all of the viewports supported by the implementation, but only
111    * signal the driver once at the end.
112    */
113   for (unsigned i = 0; i < ctx->Const.MaxViewports; i++)
114      set_viewport_no_notify(ctx, i, input.X, input.Y, input.Width, input.Height);
115
116   if (ctx->Driver.Viewport)
117      ctx->Driver.Viewport(ctx);
118}
119
120/**
121 * Set the viewport.
122 * \sa Called via glViewport() or display list execution.
123 *
124 * Flushes the vertices and calls _mesa_set_viewport() with the given
125 * parameters.
126 */
127void GLAPIENTRY
128_mesa_Viewport_no_error(GLint x, GLint y, GLsizei width, GLsizei height)
129{
130   GET_CURRENT_CONTEXT(ctx);
131   viewport(ctx, x, y, width, height);
132}
133
134void GLAPIENTRY
135_mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
136{
137   GET_CURRENT_CONTEXT(ctx);
138
139   if (MESA_VERBOSE & VERBOSE_API)
140      _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
141
142   if (width < 0 || height < 0) {
143      _mesa_error(ctx,  GL_INVALID_VALUE,
144                   "glViewport(%d, %d, %d, %d)", x, y, width, height);
145      return;
146   }
147
148   viewport(ctx, x, y, width, height);
149}
150
151
152/**
153 * Set new viewport parameters and update derived state.
154 * Usually called from _mesa_Viewport().
155 *
156 * \param ctx GL context.
157 * \param idx    Index of the viewport to be updated.
158 * \param x, y coordinates of the lower left corner of the viewport rectangle.
159 * \param width width of the viewport rectangle.
160 * \param height height of the viewport rectangle.
161 */
162void
163_mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y,
164                    GLfloat width, GLfloat height)
165{
166   clamp_viewport(ctx, &x, &y, &width, &height);
167   set_viewport_no_notify(ctx, idx, x, y, width, height);
168
169   if (ctx->Driver.Viewport)
170      ctx->Driver.Viewport(ctx);
171}
172
173static void
174viewport_array(struct gl_context *ctx, GLuint first, GLsizei count,
175               struct gl_viewport_inputs *inputs)
176{
177   for (GLsizei i = 0; i < count; i++) {
178      clamp_viewport(ctx, &inputs[i].X, &inputs[i].Y,
179                     &inputs[i].Width, &inputs[i].Height);
180
181      set_viewport_no_notify(ctx, i + first, inputs[i].X, inputs[i].Y,
182                             inputs[i].Width, inputs[i].Height);
183   }
184
185   if (ctx->Driver.Viewport)
186      ctx->Driver.Viewport(ctx);
187}
188
189void GLAPIENTRY
190_mesa_ViewportArrayv_no_error(GLuint first, GLsizei count, const GLfloat *v)
191{
192   GET_CURRENT_CONTEXT(ctx);
193
194   struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
195   viewport_array(ctx, first, count, p);
196}
197
198void GLAPIENTRY
199_mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat *v)
200{
201   int i;
202   struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
203   GET_CURRENT_CONTEXT(ctx);
204
205   if (MESA_VERBOSE & VERBOSE_API)
206      _mesa_debug(ctx, "glViewportArrayv %d %d\n", first, count);
207
208   if ((first + count) > ctx->Const.MaxViewports) {
209      _mesa_error(ctx, GL_INVALID_VALUE,
210                  "glViewportArrayv: first (%d) + count (%d) > MaxViewports "
211                  "(%d)",
212                  first, count, ctx->Const.MaxViewports);
213      return;
214   }
215
216   /* Verify width & height */
217   for (i = 0; i < count; i++) {
218      if (p[i].Width < 0 || p[i].Height < 0) {
219         _mesa_error(ctx, GL_INVALID_VALUE,
220                     "glViewportArrayv: index (%d) width or height < 0 "
221                     "(%f, %f)",
222                     i + first, p[i].Width, p[i].Height);
223         return;
224      }
225   }
226
227   viewport_array(ctx, first, count, p);
228}
229
230static void
231viewport_indexed_err(struct gl_context *ctx, GLuint index, GLfloat x, GLfloat y,
232                     GLfloat w, GLfloat h, const char *function)
233{
234   if (MESA_VERBOSE & VERBOSE_API)
235      _mesa_debug(ctx, "%s(%d, %f, %f, %f, %f)\n",
236                  function, index, x, y, w, h);
237
238   if (index >= ctx->Const.MaxViewports) {
239      _mesa_error(ctx, GL_INVALID_VALUE,
240                  "%s: index (%d) >= MaxViewports (%d)",
241                  function, index, ctx->Const.MaxViewports);
242      return;
243   }
244
245   /* Verify width & height */
246   if (w < 0 || h < 0) {
247      _mesa_error(ctx, GL_INVALID_VALUE,
248                  "%s: index (%d) width or height < 0 (%f, %f)",
249                  function, index, w, h);
250      return;
251   }
252
253   _mesa_set_viewport(ctx, index, x, y, w, h);
254}
255
256void GLAPIENTRY
257_mesa_ViewportIndexedf_no_error(GLuint index, GLfloat x, GLfloat y,
258                                GLfloat w, GLfloat h)
259{
260   GET_CURRENT_CONTEXT(ctx);
261   _mesa_set_viewport(ctx, index, x, y, w, h);
262}
263
264void GLAPIENTRY
265_mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
266                       GLfloat w, GLfloat h)
267{
268   GET_CURRENT_CONTEXT(ctx);
269   viewport_indexed_err(ctx, index, x, y, w, h, "glViewportIndexedf");
270}
271
272void GLAPIENTRY
273_mesa_ViewportIndexedfv_no_error(GLuint index, const GLfloat *v)
274{
275   GET_CURRENT_CONTEXT(ctx);
276   _mesa_set_viewport(ctx, index, v[0], v[1], v[2], v[3]);
277}
278
279void GLAPIENTRY
280_mesa_ViewportIndexedfv(GLuint index, const GLfloat *v)
281{
282   GET_CURRENT_CONTEXT(ctx);
283   viewport_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
284                        "glViewportIndexedfv");
285}
286
287static void
288set_depth_range_no_notify(struct gl_context *ctx, unsigned idx,
289                          GLclampd nearval, GLclampd farval)
290{
291   if (ctx->ViewportArray[idx].Near == nearval &&
292       ctx->ViewportArray[idx].Far == farval)
293      return;
294
295   /* The depth range is needed by program state constants. */
296   FLUSH_VERTICES(ctx, _NEW_VIEWPORT, GL_VIEWPORT_BIT);
297   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
298
299   ctx->ViewportArray[idx].Near = SATURATE(nearval);
300   ctx->ViewportArray[idx].Far = SATURATE(farval);
301}
302
303void
304_mesa_set_depth_range(struct gl_context *ctx, unsigned idx,
305                      GLclampd nearval, GLclampd farval)
306{
307   set_depth_range_no_notify(ctx, idx, nearval, farval);
308
309   if (ctx->Driver.DepthRange)
310      ctx->Driver.DepthRange(ctx);
311}
312
313/**
314 * Called by glDepthRange
315 *
316 * \param nearval  specifies the Z buffer value which should correspond to
317 *                 the near clip plane
318 * \param farval  specifies the Z buffer value which should correspond to
319 *                the far clip plane
320 */
321void GLAPIENTRY
322_mesa_DepthRange(GLclampd nearval, GLclampd farval)
323{
324   unsigned i;
325   GET_CURRENT_CONTEXT(ctx);
326
327   if (MESA_VERBOSE&VERBOSE_API)
328      _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval);
329
330   /* The GL_ARB_viewport_array spec says:
331    *
332    *     "DepthRange sets the depth range for all viewports to the same
333    *     values and is equivalent (assuming no errors are generated) to:
334    *
335    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
336    *         DepthRangeIndexed(i, n, f);"
337    *
338    * Set the depth range for all of the viewports supported by the
339    * implementation, but only signal the driver once at the end.
340    */
341   for (i = 0; i < ctx->Const.MaxViewports; i++)
342      set_depth_range_no_notify(ctx, i, nearval, farval);
343
344   if (ctx->Driver.DepthRange) {
345      ctx->Driver.DepthRange(ctx);
346   }
347}
348
349void GLAPIENTRY
350_mesa_DepthRangef(GLclampf nearval, GLclampf farval)
351{
352   _mesa_DepthRange(nearval, farval);
353}
354
355/**
356 * Update a range DepthRange values
357 *
358 * \param first   starting array index
359 * \param count   count of DepthRange items to update
360 * \param v       pointer to memory containing
361 *                GLclampd near and far clip-plane values
362 */
363static ALWAYS_INLINE void
364depth_range_arrayv(struct gl_context *ctx, GLuint first, GLsizei count,
365                   const struct gl_depthrange_inputs *const inputs)
366{
367   for (GLsizei i = 0; i < count; i++)
368      set_depth_range_no_notify(ctx, i + first, inputs[i].Near, inputs[i].Far);
369
370   if (ctx->Driver.DepthRange)
371      ctx->Driver.DepthRange(ctx);
372}
373
374void GLAPIENTRY
375_mesa_DepthRangeArrayv_no_error(GLuint first, GLsizei count, const GLclampd *v)
376{
377   GET_CURRENT_CONTEXT(ctx);
378
379   const struct gl_depthrange_inputs *const p =
380      (struct gl_depthrange_inputs *)v;
381   depth_range_arrayv(ctx, first, count, p);
382}
383
384void GLAPIENTRY
385_mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v)
386{
387   const struct gl_depthrange_inputs *const p =
388      (struct gl_depthrange_inputs *) v;
389   GET_CURRENT_CONTEXT(ctx);
390
391   if (MESA_VERBOSE & VERBOSE_API)
392      _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count);
393
394   if ((first + count) > ctx->Const.MaxViewports) {
395      _mesa_error(ctx, GL_INVALID_VALUE,
396                  "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)",
397                  first, count, ctx->Const.MaxViewports);
398      return;
399   }
400
401   depth_range_arrayv(ctx, first, count, p);
402}
403
404void GLAPIENTRY
405_mesa_DepthRangeArrayfvOES(GLuint first, GLsizei count, const GLfloat *v)
406{
407   int i;
408   GET_CURRENT_CONTEXT(ctx);
409
410   if (MESA_VERBOSE & VERBOSE_API)
411      _mesa_debug(ctx, "glDepthRangeArrayfv %d %d\n", first, count);
412
413   if ((first + count) > ctx->Const.MaxViewports) {
414      _mesa_error(ctx, GL_INVALID_VALUE,
415                  "glDepthRangeArrayfv: first (%d) + count (%d) >= MaxViewports (%d)",
416                  first, count, ctx->Const.MaxViewports);
417      return;
418   }
419
420   for (i = 0; i < count; i++)
421      set_depth_range_no_notify(ctx, i + first, v[i * 2], v[i * 2 + 1]);
422
423   if (ctx->Driver.DepthRange)
424      ctx->Driver.DepthRange(ctx);
425}
426
427/**
428 * Update a single DepthRange
429 *
430 * \param index    array index to update
431 * \param nearval  specifies the Z buffer value which should correspond to
432 *                 the near clip plane
433 * \param farval   specifies the Z buffer value which should correspond to
434 *                 the far clip plane
435 */
436void GLAPIENTRY
437_mesa_DepthRangeIndexed_no_error(GLuint index, GLclampd nearval,
438                                 GLclampd farval)
439{
440   GET_CURRENT_CONTEXT(ctx);
441   _mesa_set_depth_range(ctx, index, nearval, farval);
442}
443
444
445void GLAPIENTRY
446_mesa_DepthRangeIndexed(GLuint index, GLclampd nearval, GLclampd farval)
447{
448   GET_CURRENT_CONTEXT(ctx);
449
450   if (MESA_VERBOSE & VERBOSE_API)
451      _mesa_debug(ctx, "glDepthRangeIndexed(%d, %f, %f)\n",
452                  index, nearval, farval);
453
454   if (index >= ctx->Const.MaxViewports) {
455      _mesa_error(ctx, GL_INVALID_VALUE,
456                  "glDepthRangeIndexed: index (%d) >= MaxViewports (%d)",
457                  index, ctx->Const.MaxViewports);
458      return;
459   }
460
461   _mesa_set_depth_range(ctx, index, nearval, farval);
462}
463
464void GLAPIENTRY
465_mesa_DepthRangeIndexedfOES(GLuint index, GLfloat nearval, GLfloat farval)
466{
467   _mesa_DepthRangeIndexed(index, nearval, farval);
468}
469
470/**
471 * Initialize the context viewport attribute group.
472 * \param ctx  the GL context.
473 */
474void _mesa_init_viewport(struct gl_context *ctx)
475{
476   unsigned i;
477
478   ctx->Transform.ClipOrigin = GL_LOWER_LEFT;
479   ctx->Transform.ClipDepthMode = GL_NEGATIVE_ONE_TO_ONE;
480
481   /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
482    * so just initialize all of them.
483    */
484   for (i = 0; i < MAX_VIEWPORTS; i++) {
485      /* Viewport group */
486      ctx->ViewportArray[i].X = 0;
487      ctx->ViewportArray[i].Y = 0;
488      ctx->ViewportArray[i].Width = 0;
489      ctx->ViewportArray[i].Height = 0;
490      ctx->ViewportArray[i].Near = 0.0;
491      ctx->ViewportArray[i].Far = 1.0;
492      ctx->ViewportArray[i].SwizzleX = GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV;
493      ctx->ViewportArray[i].SwizzleY = GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV;
494      ctx->ViewportArray[i].SwizzleZ = GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV;
495      ctx->ViewportArray[i].SwizzleW = GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV;
496   }
497
498   ctx->SubpixelPrecisionBias[0] = 0;
499   ctx->SubpixelPrecisionBias[1] = 0;
500}
501
502
503static ALWAYS_INLINE void
504clip_control(struct gl_context *ctx, GLenum origin, GLenum depth, bool no_error)
505{
506   if (ctx->Transform.ClipOrigin == origin &&
507       ctx->Transform.ClipDepthMode == depth)
508      return;
509
510   if (!no_error &&
511       origin != GL_LOWER_LEFT && origin != GL_UPPER_LEFT) {
512      _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
513      return;
514   }
515
516   if (!no_error &&
517       depth != GL_NEGATIVE_ONE_TO_ONE && depth != GL_ZERO_TO_ONE) {
518      _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
519      return;
520   }
521
522   /* Affects transform state and the viewport transform */
523   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewClipControl ? 0 :
524                  _NEW_TRANSFORM | _NEW_VIEWPORT, GL_TRANSFORM_BIT);
525   ctx->NewDriverState |= ctx->DriverFlags.NewClipControl;
526
527   if (ctx->Transform.ClipOrigin != origin) {
528      ctx->Transform.ClipOrigin = origin;
529
530      /* Affects the winding order of the front face. */
531      if (ctx->DriverFlags.NewPolygonState)
532         ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
533      else
534         ctx->NewState |= _NEW_POLYGON;
535
536      if (ctx->Driver.FrontFace)
537         ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
538   }
539
540   if (ctx->Transform.ClipDepthMode != depth) {
541      ctx->Transform.ClipDepthMode = depth;
542
543      if (ctx->Driver.DepthRange)
544         ctx->Driver.DepthRange(ctx);
545   }
546}
547
548
549void GLAPIENTRY
550_mesa_ClipControl_no_error(GLenum origin, GLenum depth)
551{
552   GET_CURRENT_CONTEXT(ctx);
553   clip_control(ctx, origin, depth, true);
554}
555
556
557void GLAPIENTRY
558_mesa_ClipControl(GLenum origin, GLenum depth)
559{
560   GET_CURRENT_CONTEXT(ctx);
561
562   if (MESA_VERBOSE & VERBOSE_API)
563      _mesa_debug(ctx, "glClipControl(%s, %s)\n",
564	          _mesa_enum_to_string(origin),
565                  _mesa_enum_to_string(depth));
566
567   ASSERT_OUTSIDE_BEGIN_END(ctx);
568
569   if (!ctx->Extensions.ARB_clip_control) {
570      _mesa_error(ctx, GL_INVALID_OPERATION, "glClipControl");
571      return;
572   }
573
574   clip_control(ctx, origin, depth, false);
575}
576
577/**
578 * Computes the scaling and the translation part of the
579 * viewport transform matrix of the \param i-th viewport
580 * and writes that into \param scale and \param translate.
581 */
582void
583_mesa_get_viewport_xform(struct gl_context *ctx, unsigned i,
584                         float scale[3], float translate[3])
585{
586   float x = ctx->ViewportArray[i].X;
587   float y = ctx->ViewportArray[i].Y;
588   float half_width = 0.5f * ctx->ViewportArray[i].Width;
589   float half_height = 0.5f * ctx->ViewportArray[i].Height;
590   double n = ctx->ViewportArray[i].Near;
591   double f = ctx->ViewportArray[i].Far;
592
593   scale[0] = half_width;
594   translate[0] = half_width + x;
595   if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) {
596      scale[1] = -half_height;
597   } else {
598      scale[1] = half_height;
599   }
600   translate[1] = half_height + y;
601
602   if (ctx->Transform.ClipDepthMode == GL_NEGATIVE_ONE_TO_ONE) {
603      scale[2] = 0.5 * (f - n);
604      translate[2] = 0.5 * (n + f);
605   } else {
606      scale[2] = f - n;
607      translate[2] = n;
608   }
609}
610
611
612static void
613subpixel_precision_bias(struct gl_context *ctx, GLuint xbits, GLuint ybits)
614{
615   if (MESA_VERBOSE & VERBOSE_API)
616      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
617
618   FLUSH_VERTICES(ctx, 0, GL_VIEWPORT_BIT);
619
620   ctx->SubpixelPrecisionBias[0] = xbits;
621   ctx->SubpixelPrecisionBias[1] = ybits;
622
623   ctx->NewDriverState |=
624      ctx->DriverFlags.NewNvConservativeRasterizationParams;
625}
626
627void GLAPIENTRY
628_mesa_SubpixelPrecisionBiasNV_no_error(GLuint xbits, GLuint ybits)
629{
630   GET_CURRENT_CONTEXT(ctx);
631
632   if (MESA_VERBOSE & VERBOSE_API)
633      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
634
635   subpixel_precision_bias(ctx, xbits, ybits);
636}
637
638void GLAPIENTRY
639_mesa_SubpixelPrecisionBiasNV(GLuint xbits, GLuint ybits)
640{
641   GET_CURRENT_CONTEXT(ctx);
642
643   if (MESA_VERBOSE & VERBOSE_API)
644      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
645
646   ASSERT_OUTSIDE_BEGIN_END(ctx);
647
648   if (!ctx->Extensions.NV_conservative_raster) {
649      _mesa_error(ctx, GL_INVALID_OPERATION,
650                  "glSubpixelPrecisionBiasNV not supported");
651      return;
652   }
653
654   if (xbits > ctx->Const.MaxSubpixelPrecisionBiasBits) {
655      _mesa_error(ctx, GL_INVALID_VALUE, "glSubpixelPrecisionBiasNV");
656      return;
657   }
658
659   if (ybits > ctx->Const.MaxSubpixelPrecisionBiasBits) {
660      _mesa_error(ctx, GL_INVALID_VALUE, "glSubpixelPrecisionBiasNV");
661      return;
662   }
663
664   subpixel_precision_bias(ctx, xbits, ybits);
665}
666
667static void
668set_viewport_swizzle(struct gl_context *ctx, GLuint index,
669                     GLenum swizzlex, GLenum swizzley,
670                     GLenum swizzlez, GLenum swizzlew)
671{
672   struct gl_viewport_attrib *viewport = &ctx->ViewportArray[index];
673   if (viewport->SwizzleX == swizzlex &&
674       viewport->SwizzleY == swizzley &&
675       viewport->SwizzleZ == swizzlez &&
676       viewport->SwizzleW == swizzlew)
677      return;
678
679   FLUSH_VERTICES(ctx, _NEW_VIEWPORT, GL_VIEWPORT_BIT);
680   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
681
682   viewport->SwizzleX = swizzlex;
683   viewport->SwizzleY = swizzley;
684   viewport->SwizzleZ = swizzlez;
685   viewport->SwizzleW = swizzlew;
686}
687
688void GLAPIENTRY
689_mesa_ViewportSwizzleNV_no_error(GLuint index,
690                                 GLenum swizzlex, GLenum swizzley,
691                                 GLenum swizzlez, GLenum swizzlew)
692{
693   GET_CURRENT_CONTEXT(ctx);
694
695   if (MESA_VERBOSE & VERBOSE_API)
696      _mesa_debug(ctx, "glViewportSwizzleNV(%x, %x, %x, %x)\n",
697                  swizzlex, swizzley, swizzlez, swizzlew);
698
699   set_viewport_swizzle(ctx, index, swizzlex, swizzley, swizzlez, swizzlew);
700}
701
702static bool
703verify_viewport_swizzle(GLenum swizzle)
704{
705   return swizzle >= GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV &&
706      swizzle <= GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV;
707}
708
709void GLAPIENTRY
710_mesa_ViewportSwizzleNV(GLuint index,
711                        GLenum swizzlex, GLenum swizzley,
712                        GLenum swizzlez, GLenum swizzlew)
713{
714   GET_CURRENT_CONTEXT(ctx);
715
716   if (MESA_VERBOSE & VERBOSE_API)
717      _mesa_debug(ctx, "glViewportSwizzleNV(%x, %x, %x, %x)\n",
718                  swizzlex, swizzley, swizzlez, swizzlew);
719
720   if (!ctx->Extensions.NV_viewport_swizzle) {
721      _mesa_error(ctx, GL_INVALID_OPERATION,
722                  "glViewportSwizzleNV not supported");
723      return;
724   }
725
726   if (index >= ctx->Const.MaxViewports) {
727      _mesa_error(ctx, GL_INVALID_VALUE,
728                  "glViewportSwizzleNV: index (%d) >= MaxViewports (%d)",
729                  index, ctx->Const.MaxViewports);
730      return;
731   }
732
733   if (!verify_viewport_swizzle(swizzlex)) {
734      _mesa_error(ctx, GL_INVALID_ENUM,
735                  "glViewportSwizzleNV(swizzlex=%x)", swizzlex);
736      return;
737   }
738
739   if (!verify_viewport_swizzle(swizzley)) {
740      _mesa_error(ctx, GL_INVALID_ENUM,
741                  "glViewportSwizzleNV(swizzley=%x)", swizzley);
742      return;
743   }
744
745   if (!verify_viewport_swizzle(swizzlez)) {
746      _mesa_error(ctx, GL_INVALID_ENUM,
747                  "glViewportSwizzleNV(swizzlez=%x)", swizzlez);
748      return;
749   }
750
751   if (!verify_viewport_swizzle(swizzlew)) {
752      _mesa_error(ctx, GL_INVALID_ENUM,
753                  "glViewportSwizzleNV(swizzlew=%x)", swizzlew);
754      return;
755   }
756
757   set_viewport_swizzle(ctx, index, swizzlex, swizzley, swizzlez, swizzlew);
758}
759