1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg/**
27848b8605Smrg * \file viewport.c
28848b8605Smrg * glViewport and glDepthRange functions.
29848b8605Smrg */
30848b8605Smrg
31848b8605Smrg
32848b8605Smrg#include "context.h"
33b8e80941Smrg#include "enums.h"
34848b8605Smrg#include "macros.h"
35848b8605Smrg#include "mtypes.h"
36848b8605Smrg#include "viewport.h"
37848b8605Smrg
38848b8605Smrgstatic void
39b8e80941Smrgclamp_viewport(struct gl_context *ctx, GLfloat *x, GLfloat *y,
40b8e80941Smrg               GLfloat *width, GLfloat *height)
41848b8605Smrg{
42848b8605Smrg   /* clamp width and height to the implementation dependent range */
43b8e80941Smrg   *width  = MIN2(*width, (GLfloat) ctx->Const.MaxViewportWidth);
44b8e80941Smrg   *height = MIN2(*height, (GLfloat) ctx->Const.MaxViewportHeight);
45848b8605Smrg
46848b8605Smrg   /* The GL_ARB_viewport_array spec says:
47848b8605Smrg    *
48848b8605Smrg    *     "The location of the viewport's bottom-left corner, given by (x,y),
49848b8605Smrg    *     are clamped to be within the implementation-dependent viewport
50848b8605Smrg    *     bounds range.  The viewport bounds range [min, max] tuple may be
51848b8605Smrg    *     determined by calling GetFloatv with the symbolic constant
52848b8605Smrg    *     VIEWPORT_BOUNDS_RANGE (see section 6.1)."
53848b8605Smrg    */
54b8e80941Smrg   if (_mesa_has_ARB_viewport_array(ctx) ||
55b8e80941Smrg       _mesa_has_OES_viewport_array(ctx)) {
56b8e80941Smrg      *x = CLAMP(*x,
57b8e80941Smrg                 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
58b8e80941Smrg      *y = CLAMP(*y,
59b8e80941Smrg                 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
60848b8605Smrg   }
61b8e80941Smrg}
62b8e80941Smrg
63b8e80941Smrgstatic void
64b8e80941Smrgset_viewport_no_notify(struct gl_context *ctx, unsigned idx,
65b8e80941Smrg                       GLfloat x, GLfloat y,
66b8e80941Smrg                       GLfloat width, GLfloat height)
67b8e80941Smrg{
68b8e80941Smrg   if (ctx->ViewportArray[idx].X == x &&
69b8e80941Smrg       ctx->ViewportArray[idx].Width == width &&
70b8e80941Smrg       ctx->ViewportArray[idx].Y == y &&
71b8e80941Smrg       ctx->ViewportArray[idx].Height == height)
72b8e80941Smrg      return;
73b8e80941Smrg
74b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewViewport ? 0 : _NEW_VIEWPORT);
75b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
76848b8605Smrg
77848b8605Smrg   ctx->ViewportArray[idx].X = x;
78848b8605Smrg   ctx->ViewportArray[idx].Width = width;
79848b8605Smrg   ctx->ViewportArray[idx].Y = y;
80848b8605Smrg   ctx->ViewportArray[idx].Height = height;
81848b8605Smrg}
82848b8605Smrg
83848b8605Smrgstruct gl_viewport_inputs {
84848b8605Smrg   GLfloat X, Y;                /**< position */
85848b8605Smrg   GLfloat Width, Height;       /**< size */
86848b8605Smrg};
87848b8605Smrg
88848b8605Smrgstruct gl_depthrange_inputs {
89848b8605Smrg   GLdouble Near, Far;          /**< Depth buffer range */
90848b8605Smrg};
91848b8605Smrg
92b8e80941Smrgstatic void
93b8e80941Smrgviewport(struct gl_context *ctx, GLint x, GLint y, GLsizei width,
94b8e80941Smrg         GLsizei height)
95b8e80941Smrg{
96b8e80941Smrg   struct gl_viewport_inputs input = { x, y, width, height };
97b8e80941Smrg
98b8e80941Smrg   /* Clamp the viewport to the implementation dependent values. */
99b8e80941Smrg   clamp_viewport(ctx, &input.X, &input.Y, &input.Width, &input.Height);
100b8e80941Smrg
101b8e80941Smrg   /* The GL_ARB_viewport_array spec says:
102b8e80941Smrg    *
103b8e80941Smrg    *     "Viewport sets the parameters for all viewports to the same values
104b8e80941Smrg    *     and is equivalent (assuming no errors are generated) to:
105b8e80941Smrg    *
106b8e80941Smrg    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
107b8e80941Smrg    *         ViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);"
108b8e80941Smrg    *
109b8e80941Smrg    * Set all of the viewports supported by the implementation, but only
110b8e80941Smrg    * signal the driver once at the end.
111b8e80941Smrg    */
112b8e80941Smrg   for (unsigned i = 0; i < ctx->Const.MaxViewports; i++)
113b8e80941Smrg      set_viewport_no_notify(ctx, i, input.X, input.Y, input.Width, input.Height);
114b8e80941Smrg
115b8e80941Smrg   if (ctx->Driver.Viewport)
116b8e80941Smrg      ctx->Driver.Viewport(ctx);
117b8e80941Smrg}
118b8e80941Smrg
119848b8605Smrg/**
120848b8605Smrg * Set the viewport.
121848b8605Smrg * \sa Called via glViewport() or display list execution.
122848b8605Smrg *
123848b8605Smrg * Flushes the vertices and calls _mesa_set_viewport() with the given
124848b8605Smrg * parameters.
125848b8605Smrg */
126b8e80941Smrgvoid GLAPIENTRY
127b8e80941Smrg_mesa_Viewport_no_error(GLint x, GLint y, GLsizei width, GLsizei height)
128b8e80941Smrg{
129b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
130b8e80941Smrg   viewport(ctx, x, y, width, height);
131b8e80941Smrg}
132b8e80941Smrg
133848b8605Smrgvoid GLAPIENTRY
134848b8605Smrg_mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
135848b8605Smrg{
136848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
137848b8605Smrg
138848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
139848b8605Smrg      _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
140848b8605Smrg
141848b8605Smrg   if (width < 0 || height < 0) {
142848b8605Smrg      _mesa_error(ctx,  GL_INVALID_VALUE,
143848b8605Smrg                   "glViewport(%d, %d, %d, %d)", x, y, width, height);
144848b8605Smrg      return;
145848b8605Smrg   }
146848b8605Smrg
147b8e80941Smrg   viewport(ctx, x, y, width, height);
148848b8605Smrg}
149848b8605Smrg
150848b8605Smrg
151848b8605Smrg/**
152b8e80941Smrg * Set new viewport parameters and update derived state.
153b8e80941Smrg * Usually called from _mesa_Viewport().
154848b8605Smrg *
155848b8605Smrg * \param ctx GL context.
156848b8605Smrg * \param idx    Index of the viewport to be updated.
157848b8605Smrg * \param x, y coordinates of the lower left corner of the viewport rectangle.
158848b8605Smrg * \param width width of the viewport rectangle.
159848b8605Smrg * \param height height of the viewport rectangle.
160848b8605Smrg */
161848b8605Smrgvoid
162848b8605Smrg_mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y,
163848b8605Smrg                    GLfloat width, GLfloat height)
164848b8605Smrg{
165b8e80941Smrg   clamp_viewport(ctx, &x, &y, &width, &height);
166848b8605Smrg   set_viewport_no_notify(ctx, idx, x, y, width, height);
167848b8605Smrg
168b8e80941Smrg   if (ctx->Driver.Viewport)
169848b8605Smrg      ctx->Driver.Viewport(ctx);
170b8e80941Smrg}
171b8e80941Smrg
172b8e80941Smrgstatic void
173b8e80941Smrgviewport_array(struct gl_context *ctx, GLuint first, GLsizei count,
174b8e80941Smrg               struct gl_viewport_inputs *inputs)
175b8e80941Smrg{
176b8e80941Smrg   for (GLsizei i = 0; i < count; i++) {
177b8e80941Smrg      clamp_viewport(ctx, &inputs[i].X, &inputs[i].Y,
178b8e80941Smrg                     &inputs[i].Width, &inputs[i].Height);
179b8e80941Smrg
180b8e80941Smrg      set_viewport_no_notify(ctx, i + first, inputs[i].X, inputs[i].Y,
181b8e80941Smrg                             inputs[i].Width, inputs[i].Height);
182848b8605Smrg   }
183b8e80941Smrg
184b8e80941Smrg   if (ctx->Driver.Viewport)
185b8e80941Smrg      ctx->Driver.Viewport(ctx);
186b8e80941Smrg}
187b8e80941Smrg
188b8e80941Smrgvoid GLAPIENTRY
189b8e80941Smrg_mesa_ViewportArrayv_no_error(GLuint first, GLsizei count, const GLfloat *v)
190b8e80941Smrg{
191b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
192b8e80941Smrg
193b8e80941Smrg   struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
194b8e80941Smrg   viewport_array(ctx, first, count, p);
195848b8605Smrg}
196848b8605Smrg
197848b8605Smrgvoid GLAPIENTRY
198848b8605Smrg_mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat *v)
199848b8605Smrg{
200848b8605Smrg   int i;
201b8e80941Smrg   struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
202848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
203848b8605Smrg
204848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
205848b8605Smrg      _mesa_debug(ctx, "glViewportArrayv %d %d\n", first, count);
206848b8605Smrg
207848b8605Smrg   if ((first + count) > ctx->Const.MaxViewports) {
208848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
209848b8605Smrg                  "glViewportArrayv: first (%d) + count (%d) > MaxViewports "
210848b8605Smrg                  "(%d)",
211848b8605Smrg                  first, count, ctx->Const.MaxViewports);
212848b8605Smrg      return;
213848b8605Smrg   }
214848b8605Smrg
215848b8605Smrg   /* Verify width & height */
216848b8605Smrg   for (i = 0; i < count; i++) {
217848b8605Smrg      if (p[i].Width < 0 || p[i].Height < 0) {
218848b8605Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
219848b8605Smrg                     "glViewportArrayv: index (%d) width or height < 0 "
220848b8605Smrg                     "(%f, %f)",
221848b8605Smrg                     i + first, p[i].Width, p[i].Height);
222848b8605Smrg         return;
223848b8605Smrg      }
224848b8605Smrg   }
225848b8605Smrg
226b8e80941Smrg   viewport_array(ctx, first, count, p);
227848b8605Smrg}
228848b8605Smrg
229848b8605Smrgstatic void
230b8e80941Smrgviewport_indexed_err(struct gl_context *ctx, GLuint index, GLfloat x, GLfloat y,
231b8e80941Smrg                     GLfloat w, GLfloat h, const char *function)
232848b8605Smrg{
233848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
234848b8605Smrg      _mesa_debug(ctx, "%s(%d, %f, %f, %f, %f)\n",
235848b8605Smrg                  function, index, x, y, w, h);
236848b8605Smrg
237848b8605Smrg   if (index >= ctx->Const.MaxViewports) {
238848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
239848b8605Smrg                  "%s: index (%d) >= MaxViewports (%d)",
240848b8605Smrg                  function, index, ctx->Const.MaxViewports);
241848b8605Smrg      return;
242848b8605Smrg   }
243848b8605Smrg
244848b8605Smrg   /* Verify width & height */
245848b8605Smrg   if (w < 0 || h < 0) {
246848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
247848b8605Smrg                  "%s: index (%d) width or height < 0 (%f, %f)",
248848b8605Smrg                  function, index, w, h);
249848b8605Smrg      return;
250848b8605Smrg   }
251848b8605Smrg
252848b8605Smrg   _mesa_set_viewport(ctx, index, x, y, w, h);
253848b8605Smrg}
254848b8605Smrg
255b8e80941Smrgvoid GLAPIENTRY
256b8e80941Smrg_mesa_ViewportIndexedf_no_error(GLuint index, GLfloat x, GLfloat y,
257b8e80941Smrg                                GLfloat w, GLfloat h)
258b8e80941Smrg{
259b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
260b8e80941Smrg   _mesa_set_viewport(ctx, index, x, y, w, h);
261b8e80941Smrg}
262b8e80941Smrg
263848b8605Smrgvoid GLAPIENTRY
264848b8605Smrg_mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
265848b8605Smrg                       GLfloat w, GLfloat h)
266848b8605Smrg{
267b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
268b8e80941Smrg   viewport_indexed_err(ctx, index, x, y, w, h, "glViewportIndexedf");
269b8e80941Smrg}
270b8e80941Smrg
271b8e80941Smrgvoid GLAPIENTRY
272b8e80941Smrg_mesa_ViewportIndexedfv_no_error(GLuint index, const GLfloat *v)
273b8e80941Smrg{
274b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
275b8e80941Smrg   _mesa_set_viewport(ctx, index, v[0], v[1], v[2], v[3]);
276848b8605Smrg}
277848b8605Smrg
278848b8605Smrgvoid GLAPIENTRY
279848b8605Smrg_mesa_ViewportIndexedfv(GLuint index, const GLfloat *v)
280848b8605Smrg{
281b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
282b8e80941Smrg   viewport_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
283b8e80941Smrg                        "glViewportIndexedfv");
284848b8605Smrg}
285848b8605Smrg
286848b8605Smrgstatic void
287848b8605Smrgset_depth_range_no_notify(struct gl_context *ctx, unsigned idx,
288848b8605Smrg                          GLclampd nearval, GLclampd farval)
289848b8605Smrg{
290848b8605Smrg   if (ctx->ViewportArray[idx].Near == nearval &&
291848b8605Smrg       ctx->ViewportArray[idx].Far == farval)
292848b8605Smrg      return;
293848b8605Smrg
294b8e80941Smrg   /* The depth range is needed by program state constants. */
295b8e80941Smrg   FLUSH_VERTICES(ctx, _NEW_VIEWPORT);
296b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
297b8e80941Smrg
298848b8605Smrg   ctx->ViewportArray[idx].Near = CLAMP(nearval, 0.0, 1.0);
299848b8605Smrg   ctx->ViewportArray[idx].Far = CLAMP(farval, 0.0, 1.0);
300848b8605Smrg}
301848b8605Smrg
302848b8605Smrgvoid
303848b8605Smrg_mesa_set_depth_range(struct gl_context *ctx, unsigned idx,
304848b8605Smrg                      GLclampd nearval, GLclampd farval)
305848b8605Smrg{
306848b8605Smrg   set_depth_range_no_notify(ctx, idx, nearval, farval);
307848b8605Smrg
308848b8605Smrg   if (ctx->Driver.DepthRange)
309848b8605Smrg      ctx->Driver.DepthRange(ctx);
310848b8605Smrg}
311848b8605Smrg
312848b8605Smrg/**
313848b8605Smrg * Called by glDepthRange
314848b8605Smrg *
315848b8605Smrg * \param nearval  specifies the Z buffer value which should correspond to
316848b8605Smrg *                 the near clip plane
317848b8605Smrg * \param farval  specifies the Z buffer value which should correspond to
318848b8605Smrg *                the far clip plane
319848b8605Smrg */
320848b8605Smrgvoid GLAPIENTRY
321848b8605Smrg_mesa_DepthRange(GLclampd nearval, GLclampd farval)
322848b8605Smrg{
323848b8605Smrg   unsigned i;
324848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
325848b8605Smrg
326848b8605Smrg   if (MESA_VERBOSE&VERBOSE_API)
327848b8605Smrg      _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval);
328848b8605Smrg
329848b8605Smrg   /* The GL_ARB_viewport_array spec says:
330848b8605Smrg    *
331848b8605Smrg    *     "DepthRange sets the depth range for all viewports to the same
332848b8605Smrg    *     values and is equivalent (assuming no errors are generated) to:
333848b8605Smrg    *
334848b8605Smrg    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
335848b8605Smrg    *         DepthRangeIndexed(i, n, f);"
336848b8605Smrg    *
337848b8605Smrg    * Set the depth range for all of the viewports supported by the
338848b8605Smrg    * implementation, but only signal the driver once at the end.
339848b8605Smrg    */
340848b8605Smrg   for (i = 0; i < ctx->Const.MaxViewports; i++)
341848b8605Smrg      set_depth_range_no_notify(ctx, i, nearval, farval);
342848b8605Smrg
343848b8605Smrg   if (ctx->Driver.DepthRange) {
344848b8605Smrg      ctx->Driver.DepthRange(ctx);
345848b8605Smrg   }
346848b8605Smrg}
347848b8605Smrg
348848b8605Smrgvoid GLAPIENTRY
349848b8605Smrg_mesa_DepthRangef(GLclampf nearval, GLclampf farval)
350848b8605Smrg{
351848b8605Smrg   _mesa_DepthRange(nearval, farval);
352848b8605Smrg}
353848b8605Smrg
354848b8605Smrg/**
355848b8605Smrg * Update a range DepthRange values
356848b8605Smrg *
357848b8605Smrg * \param first   starting array index
358848b8605Smrg * \param count   count of DepthRange items to update
359848b8605Smrg * \param v       pointer to memory containing
360848b8605Smrg *                GLclampd near and far clip-plane values
361848b8605Smrg */
362b8e80941Smrgstatic ALWAYS_INLINE void
363b8e80941Smrgdepth_range_arrayv(struct gl_context *ctx, GLuint first, GLsizei count,
364b8e80941Smrg                   const struct gl_depthrange_inputs *const inputs)
365b8e80941Smrg{
366b8e80941Smrg   for (GLsizei i = 0; i < count; i++)
367b8e80941Smrg      set_depth_range_no_notify(ctx, i + first, inputs[i].Near, inputs[i].Far);
368b8e80941Smrg
369b8e80941Smrg   if (ctx->Driver.DepthRange)
370b8e80941Smrg      ctx->Driver.DepthRange(ctx);
371b8e80941Smrg}
372b8e80941Smrg
373b8e80941Smrgvoid GLAPIENTRY
374b8e80941Smrg_mesa_DepthRangeArrayv_no_error(GLuint first, GLsizei count, const GLclampd *v)
375b8e80941Smrg{
376b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
377b8e80941Smrg
378b8e80941Smrg   const struct gl_depthrange_inputs *const p =
379b8e80941Smrg      (struct gl_depthrange_inputs *)v;
380b8e80941Smrg   depth_range_arrayv(ctx, first, count, p);
381b8e80941Smrg}
382b8e80941Smrg
383848b8605Smrgvoid GLAPIENTRY
384848b8605Smrg_mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v)
385848b8605Smrg{
386848b8605Smrg   const struct gl_depthrange_inputs *const p =
387848b8605Smrg      (struct gl_depthrange_inputs *) v;
388848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
389848b8605Smrg
390848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
391848b8605Smrg      _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count);
392848b8605Smrg
393848b8605Smrg   if ((first + count) > ctx->Const.MaxViewports) {
394848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
395848b8605Smrg                  "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)",
396848b8605Smrg                  first, count, ctx->Const.MaxViewports);
397848b8605Smrg      return;
398848b8605Smrg   }
399848b8605Smrg
400b8e80941Smrg   depth_range_arrayv(ctx, first, count, p);
401b8e80941Smrg}
402b8e80941Smrg
403b8e80941Smrgvoid GLAPIENTRY
404b8e80941Smrg_mesa_DepthRangeArrayfvOES(GLuint first, GLsizei count, const GLfloat *v)
405b8e80941Smrg{
406b8e80941Smrg   int i;
407b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
408b8e80941Smrg
409b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
410b8e80941Smrg      _mesa_debug(ctx, "glDepthRangeArrayfv %d %d\n", first, count);
411b8e80941Smrg
412b8e80941Smrg   if ((first + count) > ctx->Const.MaxViewports) {
413b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
414b8e80941Smrg                  "glDepthRangeArrayfv: first (%d) + count (%d) >= MaxViewports (%d)",
415b8e80941Smrg                  first, count, ctx->Const.MaxViewports);
416b8e80941Smrg      return;
417b8e80941Smrg   }
418b8e80941Smrg
419848b8605Smrg   for (i = 0; i < count; i++)
420b8e80941Smrg      set_depth_range_no_notify(ctx, i + first, v[i * 2], v[i * 2 + 1]);
421848b8605Smrg
422848b8605Smrg   if (ctx->Driver.DepthRange)
423848b8605Smrg      ctx->Driver.DepthRange(ctx);
424848b8605Smrg}
425848b8605Smrg
426848b8605Smrg/**
427848b8605Smrg * Update a single DepthRange
428848b8605Smrg *
429848b8605Smrg * \param index    array index to update
430848b8605Smrg * \param nearval  specifies the Z buffer value which should correspond to
431848b8605Smrg *                 the near clip plane
432848b8605Smrg * \param farval   specifies the Z buffer value which should correspond to
433848b8605Smrg *                 the far clip plane
434848b8605Smrg */
435b8e80941Smrgvoid GLAPIENTRY
436b8e80941Smrg_mesa_DepthRangeIndexed_no_error(GLuint index, GLclampd nearval,
437b8e80941Smrg                                 GLclampd farval)
438b8e80941Smrg{
439b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
440b8e80941Smrg   _mesa_set_depth_range(ctx, index, nearval, farval);
441b8e80941Smrg}
442b8e80941Smrg
443b8e80941Smrg
444848b8605Smrgvoid GLAPIENTRY
445848b8605Smrg_mesa_DepthRangeIndexed(GLuint index, GLclampd nearval, GLclampd farval)
446848b8605Smrg{
447848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
448848b8605Smrg
449848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
450848b8605Smrg      _mesa_debug(ctx, "glDepthRangeIndexed(%d, %f, %f)\n",
451848b8605Smrg                  index, nearval, farval);
452848b8605Smrg
453848b8605Smrg   if (index >= ctx->Const.MaxViewports) {
454848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
455848b8605Smrg                  "glDepthRangeIndexed: index (%d) >= MaxViewports (%d)",
456848b8605Smrg                  index, ctx->Const.MaxViewports);
457848b8605Smrg      return;
458848b8605Smrg   }
459848b8605Smrg
460848b8605Smrg   _mesa_set_depth_range(ctx, index, nearval, farval);
461848b8605Smrg}
462848b8605Smrg
463b8e80941Smrgvoid GLAPIENTRY
464b8e80941Smrg_mesa_DepthRangeIndexedfOES(GLuint index, GLfloat nearval, GLfloat farval)
465b8e80941Smrg{
466b8e80941Smrg   _mesa_DepthRangeIndexed(index, nearval, farval);
467b8e80941Smrg}
468b8e80941Smrg
469848b8605Smrg/**
470848b8605Smrg * Initialize the context viewport attribute group.
471848b8605Smrg * \param ctx  the GL context.
472848b8605Smrg */
473848b8605Smrgvoid _mesa_init_viewport(struct gl_context *ctx)
474848b8605Smrg{
475848b8605Smrg   unsigned i;
476848b8605Smrg
477b8e80941Smrg   ctx->Transform.ClipOrigin = GL_LOWER_LEFT;
478b8e80941Smrg   ctx->Transform.ClipDepthMode = GL_NEGATIVE_ONE_TO_ONE;
479b8e80941Smrg
480848b8605Smrg   /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
481848b8605Smrg    * so just initialize all of them.
482848b8605Smrg    */
483848b8605Smrg   for (i = 0; i < MAX_VIEWPORTS; i++) {
484848b8605Smrg      /* Viewport group */
485848b8605Smrg      ctx->ViewportArray[i].X = 0;
486848b8605Smrg      ctx->ViewportArray[i].Y = 0;
487848b8605Smrg      ctx->ViewportArray[i].Width = 0;
488848b8605Smrg      ctx->ViewportArray[i].Height = 0;
489848b8605Smrg      ctx->ViewportArray[i].Near = 0.0;
490848b8605Smrg      ctx->ViewportArray[i].Far = 1.0;
491b8e80941Smrg   }
492b8e80941Smrg
493b8e80941Smrg   ctx->SubpixelPrecisionBias[0] = 0;
494b8e80941Smrg   ctx->SubpixelPrecisionBias[1] = 0;
495b8e80941Smrg}
496b8e80941Smrg
497b8e80941Smrg
498b8e80941Smrgstatic ALWAYS_INLINE void
499b8e80941Smrgclip_control(struct gl_context *ctx, GLenum origin, GLenum depth, bool no_error)
500b8e80941Smrg{
501b8e80941Smrg   if (ctx->Transform.ClipOrigin == origin &&
502b8e80941Smrg       ctx->Transform.ClipDepthMode == depth)
503b8e80941Smrg      return;
504b8e80941Smrg
505b8e80941Smrg   if (!no_error &&
506b8e80941Smrg       origin != GL_LOWER_LEFT && origin != GL_UPPER_LEFT) {
507b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
508b8e80941Smrg      return;
509b8e80941Smrg   }
510b8e80941Smrg
511b8e80941Smrg   if (!no_error &&
512b8e80941Smrg       depth != GL_NEGATIVE_ONE_TO_ONE && depth != GL_ZERO_TO_ONE) {
513b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
514b8e80941Smrg      return;
515b8e80941Smrg   }
516b8e80941Smrg
517b8e80941Smrg   /* Affects transform state and the viewport transform */
518b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewClipControl ? 0 :
519b8e80941Smrg                  _NEW_TRANSFORM | _NEW_VIEWPORT);
520b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewClipControl;
521b8e80941Smrg
522b8e80941Smrg   if (ctx->Transform.ClipOrigin != origin) {
523b8e80941Smrg      ctx->Transform.ClipOrigin = origin;
524848b8605Smrg
525b8e80941Smrg      /* Affects the winding order of the front face. */
526b8e80941Smrg      if (ctx->DriverFlags.NewPolygonState)
527b8e80941Smrg         ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
528b8e80941Smrg      else
529b8e80941Smrg         ctx->NewState |= _NEW_POLYGON;
530b8e80941Smrg
531b8e80941Smrg      if (ctx->Driver.FrontFace)
532b8e80941Smrg         ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
533b8e80941Smrg   }
534b8e80941Smrg
535b8e80941Smrg   if (ctx->Transform.ClipDepthMode != depth) {
536b8e80941Smrg      ctx->Transform.ClipDepthMode = depth;
537b8e80941Smrg
538b8e80941Smrg      if (ctx->Driver.DepthRange)
539b8e80941Smrg         ctx->Driver.DepthRange(ctx);
540848b8605Smrg   }
541848b8605Smrg}
542848b8605Smrg
543848b8605Smrg
544b8e80941Smrgvoid GLAPIENTRY
545b8e80941Smrg_mesa_ClipControl_no_error(GLenum origin, GLenum depth)
546b8e80941Smrg{
547b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
548b8e80941Smrg   clip_control(ctx, origin, depth, true);
549b8e80941Smrg}
550b8e80941Smrg
551b8e80941Smrg
552b8e80941Smrgvoid GLAPIENTRY
553b8e80941Smrg_mesa_ClipControl(GLenum origin, GLenum depth)
554b8e80941Smrg{
555b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
556b8e80941Smrg
557b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
558b8e80941Smrg      _mesa_debug(ctx, "glClipControl(%s, %s)\n",
559b8e80941Smrg	          _mesa_enum_to_string(origin),
560b8e80941Smrg                  _mesa_enum_to_string(depth));
561b8e80941Smrg
562b8e80941Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
563b8e80941Smrg
564b8e80941Smrg   if (!ctx->Extensions.ARB_clip_control) {
565b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glClipControl");
566b8e80941Smrg      return;
567b8e80941Smrg   }
568b8e80941Smrg
569b8e80941Smrg   clip_control(ctx, origin, depth, false);
570b8e80941Smrg}
571b8e80941Smrg
572b8e80941Smrg/**
573b8e80941Smrg * Computes the scaling and the translation part of the
574b8e80941Smrg * viewport transform matrix of the \param i-th viewport
575b8e80941Smrg * and writes that into \param scale and \param translate.
576848b8605Smrg */
577b8e80941Smrgvoid
578b8e80941Smrg_mesa_get_viewport_xform(struct gl_context *ctx, unsigned i,
579b8e80941Smrg                         float scale[3], float translate[3])
580848b8605Smrg{
581b8e80941Smrg   float x = ctx->ViewportArray[i].X;
582b8e80941Smrg   float y = ctx->ViewportArray[i].Y;
583b8e80941Smrg   float half_width = 0.5f * ctx->ViewportArray[i].Width;
584b8e80941Smrg   float half_height = 0.5f * ctx->ViewportArray[i].Height;
585b8e80941Smrg   double n = ctx->ViewportArray[i].Near;
586b8e80941Smrg   double f = ctx->ViewportArray[i].Far;
587b8e80941Smrg
588b8e80941Smrg   scale[0] = half_width;
589b8e80941Smrg   translate[0] = half_width + x;
590b8e80941Smrg   if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) {
591b8e80941Smrg      scale[1] = -half_height;
592b8e80941Smrg   } else {
593b8e80941Smrg      scale[1] = half_height;
594b8e80941Smrg   }
595b8e80941Smrg   translate[1] = half_height + y;
596b8e80941Smrg
597b8e80941Smrg   if (ctx->Transform.ClipDepthMode == GL_NEGATIVE_ONE_TO_ONE) {
598b8e80941Smrg      scale[2] = 0.5 * (f - n);
599b8e80941Smrg      translate[2] = 0.5 * (n + f);
600b8e80941Smrg   } else {
601b8e80941Smrg      scale[2] = f - n;
602b8e80941Smrg      translate[2] = n;
603b8e80941Smrg   }
604b8e80941Smrg}
605b8e80941Smrg
606b8e80941Smrg
607b8e80941Smrgstatic void
608b8e80941Smrgsubpixel_precision_bias(struct gl_context *ctx, GLuint xbits, GLuint ybits)
609b8e80941Smrg{
610b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
611b8e80941Smrg      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
612b8e80941Smrg
613b8e80941Smrg   ctx->SubpixelPrecisionBias[0] = xbits;
614b8e80941Smrg   ctx->SubpixelPrecisionBias[1] = ybits;
615848b8605Smrg
616b8e80941Smrg   FLUSH_VERTICES(ctx, 0);
617b8e80941Smrg   ctx->NewDriverState |=
618b8e80941Smrg      ctx->DriverFlags.NewNvConservativeRasterizationParams;
619848b8605Smrg}
620848b8605Smrg
621b8e80941Smrgvoid GLAPIENTRY
622b8e80941Smrg_mesa_SubpixelPrecisionBiasNV_no_error(GLuint xbits, GLuint ybits)
623b8e80941Smrg{
624b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
625b8e80941Smrg
626b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
627b8e80941Smrg      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
628b8e80941Smrg
629b8e80941Smrg   subpixel_precision_bias(ctx, xbits, ybits);
630b8e80941Smrg}
631b8e80941Smrg
632b8e80941Smrgvoid GLAPIENTRY
633b8e80941Smrg_mesa_SubpixelPrecisionBiasNV(GLuint xbits, GLuint ybits)
634b8e80941Smrg{
635b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
636b8e80941Smrg
637b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
638b8e80941Smrg      _mesa_debug(ctx, "glSubpixelPrecisionBiasNV(%u, %u)\n", xbits, ybits);
639b8e80941Smrg
640b8e80941Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
641b8e80941Smrg
642b8e80941Smrg   if (!ctx->Extensions.NV_conservative_raster) {
643b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
644b8e80941Smrg                  "glSubpixelPrecisionBiasNV not supported");
645b8e80941Smrg      return;
646b8e80941Smrg   }
647b8e80941Smrg
648b8e80941Smrg   if (xbits > ctx->Const.MaxSubpixelPrecisionBiasBits) {
649b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glSubpixelPrecisionBiasNV");
650b8e80941Smrg      return;
651b8e80941Smrg   }
652b8e80941Smrg
653b8e80941Smrg   if (ybits > ctx->Const.MaxSubpixelPrecisionBiasBits) {
654b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glSubpixelPrecisionBiasNV");
655b8e80941Smrg      return;
656b8e80941Smrg   }
657b8e80941Smrg
658b8e80941Smrg   subpixel_precision_bias(ctx, xbits, ybits);
659b8e80941Smrg}
660