glthread: track instance divisor changes
[mesa.git] / src / mesa / main / viewport.c
index a58697ab3704036f11848b4323e3ed99736dcb89..a501e245626f2acb45d98ea339db627462d17e09 100644 (file)
@@ -1,6 +1,5 @@
 /*
  * Mesa 3-D graphics library
- * Version:  7.5
  *
  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
 
 
 
 
 #include "context.h"
+#include "enums.h"
 #include "macros.h"
 #include "mtypes.h"
 #include "viewport.h"
 
+static void
+clamp_viewport(struct gl_context *ctx, GLfloat *x, GLfloat *y,
+               GLfloat *width, GLfloat *height)
+{
+   /* clamp width and height to the implementation dependent range */
+   *width  = MIN2(*width, (GLfloat) ctx->Const.MaxViewportWidth);
+   *height = MIN2(*height, (GLfloat) ctx->Const.MaxViewportHeight);
+
+   /* The GL_ARB_viewport_array spec says:
+    *
+    *     "The location of the viewport's bottom-left corner, given by (x,y),
+    *     are clamped to be within the implementation-dependent viewport
+    *     bounds range.  The viewport bounds range [min, max] tuple may be
+    *     determined by calling GetFloatv with the symbolic constant
+    *     VIEWPORT_BOUNDS_RANGE (see section 6.1)."
+    */
+   if (_mesa_has_ARB_viewport_array(ctx) ||
+       _mesa_has_OES_viewport_array(ctx)) {
+      *x = CLAMP(*x,
+                 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
+      *y = CLAMP(*y,
+                 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
+   }
+}
+
+static void
+set_viewport_no_notify(struct gl_context *ctx, unsigned idx,
+                       GLfloat x, GLfloat y,
+                       GLfloat width, GLfloat height)
+{
+   if (ctx->ViewportArray[idx].X == x &&
+       ctx->ViewportArray[idx].Width == width &&
+       ctx->ViewportArray[idx].Y == y &&
+       ctx->ViewportArray[idx].Height == height)
+      return;
+
+   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewViewport ? 0 : _NEW_VIEWPORT);
+   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
+
+   ctx->ViewportArray[idx].X = x;
+   ctx->ViewportArray[idx].Width = width;
+   ctx->ViewportArray[idx].Y = y;
+   ctx->ViewportArray[idx].Height = height;
+}
+
+struct gl_viewport_inputs {
+   GLfloat X, Y;                /**< position */
+   GLfloat Width, Height;       /**< size */
+};
+
+struct gl_depthrange_inputs {
+   GLdouble Near, Far;          /**< Depth buffer range */
+};
+
+static void
+viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei width,
+         GLsizei height)
+{
+   struct gl_viewport_inputs input = { x, y, width, height };
+
+   /* Clamp the viewport to the implementation dependent values. */
+   clamp_viewport(ctx, &input.X, &input.Y, &input.Width, &input.Height);
+
+   /* The GL_ARB_viewport_array spec says:
+    *
+    *     "Viewport sets the parameters for all viewports to the same values
+    *     and is equivalent (assuming no errors are generated) to:
+    *
+    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
+    *         ViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);"
+    *
+    * Set all of the viewports supported by the implementation, but only
+    * signal the driver once at the end.
+    */
+   for (unsigned i = 0; i < ctx->Const.MaxViewports; i++)
+      set_viewport_no_notify(ctx, i, input.X, input.Y, input.Width, input.Height);
+
+   if (ctx->Driver.Viewport)
+      ctx->Driver.Viewport(ctx);
+}
 
 /**
  * Set the viewport.
  * Flushes the vertices and calls _mesa_set_viewport() with the given
  * parameters.
  */
+void GLAPIENTRY
+_mesa_Viewport_no_error(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   viewport(ctx, x, y, width, height);
+}
+
 void GLAPIENTRY
 _mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
 {
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-   _mesa_set_viewport(ctx, x, y, width, height);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
+
+   if (width < 0 || height < 0) {
+      _mesa_error(ctx,  GL_INVALID_VALUE,
+                   "glViewport(%d, %d, %d, %d)", x, y, width, height);
+      return;
+   }
+
+   viewport(ctx, x, y, width, height);
 }
 
 
 /**
- * Set new viewport parameters and update derived state (the _WindowMap
- * matrix).  Usually called from _mesa_Viewport().
+ * Set new viewport parameters and update derived state.
+ * Usually called from _mesa_Viewport().
  * 
  * \param ctx GL context.
+ * \param idx    Index of the viewport to be updated.
  * \param x, y coordinates of the lower left corner of the viewport rectangle.
  * \param width width of the viewport rectangle.
  * \param height height of the viewport rectangle.
  */
 void
-_mesa_set_viewport(struct gl_context *ctx, GLint x, GLint y,
-                    GLsizei width, GLsizei height)
+_mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y,
+                    GLfloat width, GLfloat height)
 {
+   clamp_viewport(ctx, &x, &y, &width, &height);
+   set_viewport_no_notify(ctx, idx, x, y, width, height);
+
+   if (ctx->Driver.Viewport)
+      ctx->Driver.Viewport(ctx);
+}
+
+static void
+viewport_array(struct gl_context *ctx, GLuint first, GLsizei count,
+               struct gl_viewport_inputs *inputs)
+{
+   for (GLsizei i = 0; i < count; i++) {
+      clamp_viewport(ctx, &inputs[i].X, &inputs[i].Y,
+                     &inputs[i].Width, &inputs[i].Height);
+
+      set_viewport_no_notify(ctx, i + first, inputs[i].X, inputs[i].Y,
+                             inputs[i].Width, inputs[i].Height);
+   }
+
+   if (ctx->Driver.Viewport)
+      ctx->Driver.Viewport(ctx);
+}
+
+void GLAPIENTRY
+_mesa_ViewportArrayv_no_error(GLuint first, GLsizei count, const GLfloat *v)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
+   viewport_array(ctx, first, count, p);
+}
+
+void GLAPIENTRY
+_mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat *v)
+{
+   int i;
+   struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
+   GET_CURRENT_CONTEXT(ctx);
+
    if (MESA_VERBOSE & VERBOSE_API)
-      _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
+      _mesa_debug(ctx, "glViewportArrayv %d %d\n", first, count);
 
-   if (width < 0 || height < 0) {
-      _mesa_error(ctx,  GL_INVALID_VALUE,
-                   "glViewport(%d, %d, %d, %d)", x, y, width, height);
+   if ((first + count) > ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glViewportArrayv: first (%d) + count (%d) > MaxViewports "
+                  "(%d)",
+                  first, count, ctx->Const.MaxViewports);
       return;
    }
 
-   /* clamp width and height to the implementation dependent range */
-   width  = MIN2(width, (GLsizei) ctx->Const.MaxViewportWidth);
-   height = MIN2(height, (GLsizei) ctx->Const.MaxViewportHeight);
-
-   ctx->Viewport.X = x;
-   ctx->Viewport.Width = width;
-   ctx->Viewport.Y = y;
-   ctx->Viewport.Height = height;
-   ctx->NewState |= _NEW_VIEWPORT;
-
-#if 1
-   /* XXX remove this someday.  Currently the DRI drivers rely on
-    * the WindowMap matrix being up to date in the driver's Viewport
-    * and DepthRange functions.
-    */
-   _math_matrix_viewport(&ctx->Viewport._WindowMap,
-                         ctx->Viewport.X, ctx->Viewport.Y,
-                         ctx->Viewport.Width, ctx->Viewport.Height,
-                         ctx->Viewport.Near, ctx->Viewport.Far,
-                         ctx->DrawBuffer->_DepthMaxF);
-#endif
+   /* Verify width & height */
+   for (i = 0; i < count; i++) {
+      if (p[i].Width < 0 || p[i].Height < 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glViewportArrayv: index (%d) width or height < 0 "
+                     "(%f, %f)",
+                     i + first, p[i].Width, p[i].Height);
+         return;
+      }
+   }
+
+   viewport_array(ctx, first, count, p);
+}
 
-   if (ctx->Driver.Viewport) {
-      /* Many drivers will use this call to check for window size changes
-       * and reallocate the z/stencil/accum/etc buffers if needed.
-       */
-      ctx->Driver.Viewport(ctx, x, y, width, height);
+static void
+viewport_indexed_err(struct gl_context *ctx, GLuint index, GLfloat x, GLfloat y,
+                     GLfloat w, GLfloat h, const char *function)
+{
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "%s(%d, %f, %f, %f, %f)\n",
+                  function, index, x, y, w, h);
+
+   if (index >= ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s: index (%d) >= MaxViewports (%d)",
+                  function, index, ctx->Const.MaxViewports);
+      return;
    }
+
+   /* Verify width & height */
+   if (w < 0 || h < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s: index (%d) width or height < 0 (%f, %f)",
+                  function, index, w, h);
+      return;
+   }
+
+   _mesa_set_viewport(ctx, index, x, y, w, h);
+}
+
+void GLAPIENTRY
+_mesa_ViewportIndexedf_no_error(GLuint index, GLfloat x, GLfloat y,
+                                GLfloat w, GLfloat h)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   _mesa_set_viewport(ctx, index, x, y, w, h);
 }
 
+void GLAPIENTRY
+_mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
+                       GLfloat w, GLfloat h)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   viewport_indexed_err(ctx, index, x, y, w, h, "glViewportIndexedf");
+}
+
+void GLAPIENTRY
+_mesa_ViewportIndexedfv_no_error(GLuint index, const GLfloat *v)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   _mesa_set_viewport(ctx, index, v[0], v[1], v[2], v[3]);
+}
+
+void GLAPIENTRY
+_mesa_ViewportIndexedfv(GLuint index, const GLfloat *v)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   viewport_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
+                        "glViewportIndexedfv");
+}
+
+static void
+set_depth_range_no_notify(struct gl_context *ctx, unsigned idx,
+                          GLclampd nearval, GLclampd farval)
+{
+   if (ctx->ViewportArray[idx].Near == nearval &&
+       ctx->ViewportArray[idx].Far == farval)
+      return;
+
+   /* The depth range is needed by program state constants. */
+   FLUSH_VERTICES(ctx, _NEW_VIEWPORT);
+   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
+
+   ctx->ViewportArray[idx].Near = CLAMP(nearval, 0.0, 1.0);
+   ctx->ViewportArray[idx].Far = CLAMP(farval, 0.0, 1.0);
+}
+
+void
+_mesa_set_depth_range(struct gl_context *ctx, unsigned idx,
+                      GLclampd nearval, GLclampd farval)
+{
+   set_depth_range_no_notify(ctx, idx, nearval, farval);
+
+   if (ctx->Driver.DepthRange)
+      ctx->Driver.DepthRange(ctx);
+}
 
 /**
  * Called by glDepthRange
@@ -115,34 +320,28 @@ _mesa_set_viewport(struct gl_context *ctx, GLint x, GLint y,
 void GLAPIENTRY
 _mesa_DepthRange(GLclampd nearval, GLclampd farval)
 {
+   unsigned i;
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    if (MESA_VERBOSE&VERBOSE_API)
       _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval);
 
-   if (ctx->Viewport.Near == nearval &&
-       ctx->Viewport.Far == farval)
-      return;
-
-   ctx->Viewport.Near = (GLfloat) CLAMP(nearval, 0.0, 1.0);
-   ctx->Viewport.Far = (GLfloat) CLAMP(farval, 0.0, 1.0);
-   ctx->NewState |= _NEW_VIEWPORT;
-
-#if 1
-   /* XXX remove this someday.  Currently the DRI drivers rely on
-    * the WindowMap matrix being up to date in the driver's Viewport
-    * and DepthRange functions.
+   /* The GL_ARB_viewport_array spec says:
+    *
+    *     "DepthRange sets the depth range for all viewports to the same
+    *     values and is equivalent (assuming no errors are generated) to:
+    *
+    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
+    *         DepthRangeIndexed(i, n, f);"
+    *
+    * Set the depth range for all of the viewports supported by the
+    * implementation, but only signal the driver once at the end.
     */
-   _math_matrix_viewport(&ctx->Viewport._WindowMap,
-                         ctx->Viewport.X, ctx->Viewport.Y,
-                         ctx->Viewport.Width, ctx->Viewport.Height,
-                         ctx->Viewport.Near, ctx->Viewport.Far,
-                         ctx->DrawBuffer->_DepthMaxF);
-#endif
+   for (i = 0; i < ctx->Const.MaxViewports; i++)
+      set_depth_range_no_notify(ctx, i, nearval, farval);
 
    if (ctx->Driver.DepthRange) {
-      ctx->Driver.DepthRange(ctx, nearval, farval);
+      ctx->Driver.DepthRange(ctx);
    }
 }
 
@@ -152,34 +351,407 @@ _mesa_DepthRangef(GLclampf nearval, GLclampf farval)
    _mesa_DepthRange(nearval, farval);
 }
 
+/**
+ * Update a range DepthRange values
+ *
+ * \param first   starting array index
+ * \param count   count of DepthRange items to update
+ * \param v       pointer to memory containing
+ *                GLclampd near and far clip-plane values
+ */
+static ALWAYS_INLINE void
+depth_range_arrayv(struct gl_context *ctx, GLuint first, GLsizei count,
+                   const struct gl_depthrange_inputs *const inputs)
+{
+   for (GLsizei i = 0; i < count; i++)
+      set_depth_range_no_notify(ctx, i + first, inputs[i].Near, inputs[i].Far);
+
+   if (ctx->Driver.DepthRange)
+      ctx->Driver.DepthRange(ctx);
+}
+
+void GLAPIENTRY
+_mesa_DepthRangeArrayv_no_error(GLuint first, GLsizei count, const GLclampd *v)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   const struct gl_depthrange_inputs *const p =
+      (struct gl_depthrange_inputs *)v;
+   depth_range_arrayv(ctx, first, count, p);
+}
+
+void GLAPIENTRY
+_mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v)
+{
+   const struct gl_depthrange_inputs *const p =
+      (struct gl_depthrange_inputs *) v;
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count);
+
+   if ((first + count) > ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)",
+                  first, count, ctx->Const.MaxViewports);
+      return;
+   }
+
+   depth_range_arrayv(ctx, first, count, p);
+}
+
+void GLAPIENTRY
+_mesa_DepthRangeArrayfvOES(GLuint first, GLsizei count, const GLfloat *v)
+{
+   int i;
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glDepthRangeArrayfv %d %d\n", first, count);
+
+   if ((first + count) > ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glDepthRangeArrayfv: first (%d) + count (%d) >= MaxViewports (%d)",
+                  first, count, ctx->Const.MaxViewports);
+      return;
+   }
+
+   for (i = 0; i < count; i++)
+      set_depth_range_no_notify(ctx, i + first, v[i * 2], v[i * 2 + 1]);
+
+   if (ctx->Driver.DepthRange)
+      ctx->Driver.DepthRange(ctx);
+}
+
+/**
+ * Update a single DepthRange
+ *
+ * \param index    array index to update
+ * \param nearval  specifies the Z buffer value which should correspond to
+ *                 the near clip plane
+ * \param farval   specifies the Z buffer value which should correspond to
+ *                 the far clip plane
+ */
+void GLAPIENTRY
+_mesa_DepthRangeIndexed_no_error(GLuint index, GLclampd nearval,
+                                 GLclampd farval)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   _mesa_set_depth_range(ctx, index, nearval, farval);
+}
+
+
+void GLAPIENTRY
+_mesa_DepthRangeIndexed(GLuint index, GLclampd nearval, GLclampd farval)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glDepthRangeIndexed(%d, %f, %f)\n",
+                  index, nearval, farval);
+
+   if (index >= ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glDepthRangeIndexed: index (%d) >= MaxViewports (%d)",
+                  index, ctx->Const.MaxViewports);
+      return;
+   }
+
+   _mesa_set_depth_range(ctx, index, nearval, farval);
+}
+
+void GLAPIENTRY
+_mesa_DepthRangeIndexedfOES(GLuint index, GLfloat nearval, GLfloat farval)
+{
+   _mesa_DepthRangeIndexed(index, nearval, farval);
+}
+
 /** 
  * Initialize the context viewport attribute group.
  * \param ctx  the GL context.
  */
 void _mesa_init_viewport(struct gl_context *ctx)
 {
-   GLfloat depthMax = 65535.0F; /* sorf of arbitrary */
+   unsigned i;
+
+   ctx->Transform.ClipOrigin = GL_LOWER_LEFT;
+   ctx->Transform.ClipDepthMode = GL_NEGATIVE_ONE_TO_ONE;
 
-   /* Viewport group */
-   ctx->Viewport.X = 0;
-   ctx->Viewport.Y = 0;
-   ctx->Viewport.Width = 0;
-   ctx->Viewport.Height = 0;
-   ctx->Viewport.Near = 0.0;
-   ctx->Viewport.Far = 1.0;
-   _math_matrix_ctr(&ctx->Viewport._WindowMap);
+   /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
+    * so just initialize all of them.
+    */
+   for (i = 0; i < MAX_VIEWPORTS; i++) {
+      /* Viewport group */
+      ctx->ViewportArray[i].X = 0;
+      ctx->ViewportArray[i].Y = 0;
+      ctx->ViewportArray[i].Width = 0;
+      ctx->ViewportArray[i].Height = 0;
+      ctx->ViewportArray[i].Near = 0.0;
+      ctx->ViewportArray[i].Far = 1.0;
+      ctx->ViewportArray[i].SwizzleX = GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV;
+      ctx->ViewportArray[i].SwizzleY = GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV;
+      ctx->ViewportArray[i].SwizzleZ = GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV;
+      ctx->ViewportArray[i].SwizzleW = GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV;
+   }
 
-   _math_matrix_viewport(&ctx->Viewport._WindowMap, 0, 0, 0, 0,
-                         0.0F, 1.0F, depthMax);
+   ctx->SubpixelPrecisionBias[0] = 0;
+   ctx->SubpixelPrecisionBias[1] = 0;
 }
 
 
-/** 
- * Free the context viewport attribute group data.
- * \param ctx  the GL context.
+static ALWAYS_INLINE void
+clip_control(struct gl_context *ctx, GLenum origin, GLenum depth, bool no_error)
+{
+   if (ctx->Transform.ClipOrigin == origin &&
+       ctx->Transform.ClipDepthMode == depth)
+      return;
+
+   if (!no_error &&
+       origin != GL_LOWER_LEFT && origin != GL_UPPER_LEFT) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
+      return;
+   }
+
+   if (!no_error &&
+       depth != GL_NEGATIVE_ONE_TO_ONE && depth != GL_ZERO_TO_ONE) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
+      return;
+   }
+
+   /* Affects transform state and the viewport transform */
+   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewClipControl ? 0 :
+                  _NEW_TRANSFORM | _NEW_VIEWPORT);
+   ctx->NewDriverState |= ctx->DriverFlags.NewClipControl;
+
+   if (ctx->Transform.ClipOrigin != origin) {
+      ctx->Transform.ClipOrigin = origin;
+
+      /* Affects the winding order of the front face. */
+      if (ctx->DriverFlags.NewPolygonState)
+         ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
+      else
+         ctx->NewState |= _NEW_POLYGON;
+
+      if (ctx->Driver.FrontFace)
+         ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
+   }
+
+   if (ctx->Transform.ClipDepthMode != depth) {
+      ctx->Transform.ClipDepthMode = depth;
+
+      if (ctx->Driver.DepthRange)
+         ctx->Driver.DepthRange(ctx);
+   }
+}
+
+
+void GLAPIENTRY
+_mesa_ClipControl_no_error(GLenum origin, GLenum depth)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   clip_control(ctx, origin, depth, true);
+}
+
+
+void GLAPIENTRY
+_mesa_ClipControl(GLenum origin, GLenum depth)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glClipControl(%s, %s)\n",
+                 _mesa_enum_to_string(origin),
+                  _mesa_enum_to_string(depth));
+
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ARB_clip_control) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glClipControl");
+      return;
+   }
+
+   clip_control(ctx, origin, depth, false);
+}
+
+/**
+ * Computes the scaling and the translation part of the
+ * viewport transform matrix of the \param i-th viewport
+ * and writes that into \param scale and \param translate.
  */
-void _mesa_free_viewport_data(struct gl_context *ctx)
+void
+_mesa_get_viewport_xform(struct gl_context *ctx, unsigned i,
+                         float scale[3], float translate[3])
 {
-   _math_matrix_dtr(&ctx->Viewport._WindowMap);
+   float x = ctx->ViewportArray[i].X;
+   float y = ctx->ViewportArray[i].Y;
+   float half_width = 0.5f * ctx->ViewportArray[i].Width;
+   float half_height = 0.5f * ctx->ViewportArray[i].Height;
+   double n = ctx->ViewportArray[i].Near;
+   double f = ctx->ViewportArray[i].Far;
+
+   scale[0] = half_width;
+   translate[0] = half_width + x;
+   if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) {
+      scale[1] = -half_height;
+   } else {
+      scale[1] = half_height;
+   }
+   translate[1] = half_height + y;
+
+   if (ctx->Transform.ClipDepthMode == GL_NEGATIVE_ONE_TO_ONE) {
+      scale[2] = 0.5 * (f - n);
+      translate[2] = 0.5 * (n + f);
+   } else {
+      scale[2] = f - n;
+      translate[2] = n;
+   }
 }
 
+
+static void
+subpixel_precision_bias(struct gl_context *ctx, GLuint xbits, GLuint ybits)
+{
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
+
+   FLUSH_VERTICES(ctx, 0);
+
+   ctx->SubpixelPrecisionBias[0] = xbits;
+   ctx->SubpixelPrecisionBias[1] = ybits;
+
+   ctx->NewDriverState |=
+      ctx->DriverFlags.NewNvConservativeRasterizationParams;
+}
+
+void GLAPIENTRY
+_mesa_SubpixelPrecisionBiasNV_no_error(GLuint xbits, GLuint ybits)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
+
+   subpixel_precision_bias(ctx, xbits, ybits);
+}
+
+void GLAPIENTRY
+_mesa_SubpixelPrecisionBiasNV(GLuint xbits, GLuint ybits)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
+
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.NV_conservative_raster) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glSubpixelPrecisionBiasNV not supported");
+      return;
+   }
+
+   if (xbits > ctx->Const.MaxSubpixelPrecisionBiasBits) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glSubpixelPrecisionBiasNV");
+      return;
+   }
+
+   if (ybits > ctx->Const.MaxSubpixelPrecisionBiasBits) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glSubpixelPrecisionBiasNV");
+      return;
+   }
+
+   subpixel_precision_bias(ctx, xbits, ybits);
+}
+
+static void
+set_viewport_swizzle(struct gl_context *ctx, GLuint index,
+                     GLenum swizzlex, GLenum swizzley,
+                     GLenum swizzlez, GLenum swizzlew)
+{
+   struct gl_viewport_attrib *viewport = &ctx->ViewportArray[index];
+   if (viewport->SwizzleX == swizzlex &&
+       viewport->SwizzleY == swizzley &&
+       viewport->SwizzleZ == swizzlez &&
+       viewport->SwizzleW == swizzlew)
+      return;
+
+   FLUSH_VERTICES(ctx, _NEW_VIEWPORT);
+   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
+
+   viewport->SwizzleX = swizzlex;
+   viewport->SwizzleY = swizzley;
+   viewport->SwizzleZ = swizzlez;
+   viewport->SwizzleW = swizzlew;
+}
+
+void GLAPIENTRY
+_mesa_ViewportSwizzleNV_no_error(GLuint index,
+                                 GLenum swizzlex, GLenum swizzley,
+                                 GLenum swizzlez, GLenum swizzlew)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glViewportSwizzleNV(%x, %x, %x, %x)\n",
+                  swizzlex, swizzley, swizzlez, swizzlew);
+
+   set_viewport_swizzle(ctx, index, swizzlex, swizzley, swizzlez, swizzlew);
+}
+
+static bool
+verify_viewport_swizzle(GLenum swizzle)
+{
+   return swizzle >= GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV &&
+      swizzle <= GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV;
+}
+
+void GLAPIENTRY
+_mesa_ViewportSwizzleNV(GLuint index,
+                        GLenum swizzlex, GLenum swizzley,
+                        GLenum swizzlez, GLenum swizzlew)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glViewportSwizzleNV(%x, %x, %x, %x)\n",
+                  swizzlex, swizzley, swizzlez, swizzlew);
+
+   if (!ctx->Extensions.NV_viewport_swizzle) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glViewportSwizzleNV not supported");
+      return;
+   }
+
+   if (index >= ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glViewportSwizzleNV: index (%d) >= MaxViewports (%d)",
+                  index, ctx->Const.MaxViewports);
+      return;
+   }
+
+   if (!verify_viewport_swizzle(swizzlex)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glViewportSwizzleNV(swizzlex=%x)", swizzlex);
+      return;
+   }
+
+   if (!verify_viewport_swizzle(swizzley)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glViewportSwizzleNV(swizzley=%x)", swizzley);
+      return;
+   }
+
+   if (!verify_viewport_swizzle(swizzlez)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glViewportSwizzleNV(swizzlez=%x)", swizzlez);
+      return;
+   }
+
+   if (!verify_viewport_swizzle(swizzlew)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glViewportSwizzleNV(swizzlew=%x)", swizzlew);
+      return;
+   }
+
+   set_viewport_swizzle(ctx, index, swizzlex, swizzley, swizzlez, swizzlew);
+}