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