mesa/gallium: Signal _NEW_TRANSFORM from glClipControl.
[mesa.git] / src / mesa / main / viewport.c
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
38 static void
39 set_viewport_no_notify(struct gl_context *ctx, unsigned idx,
40 GLfloat x, GLfloat y,
41 GLfloat width, GLfloat height)
42 {
43 double scale[3], translate[3];
44
45 /* clamp width and height to the implementation dependent range */
46 width = MIN2(width, (GLfloat) ctx->Const.MaxViewportWidth);
47 height = MIN2(height, (GLfloat) ctx->Const.MaxViewportHeight);
48
49 /* The GL_ARB_viewport_array spec says:
50 *
51 * "The location of the viewport's bottom-left corner, given by (x,y),
52 * are clamped to be within the implementation-dependent viewport
53 * bounds range. The viewport bounds range [min, max] tuple may be
54 * determined by calling GetFloatv with the symbolic constant
55 * VIEWPORT_BOUNDS_RANGE (see section 6.1)."
56 */
57 if (ctx->Extensions.ARB_viewport_array) {
58 x = CLAMP(x,
59 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
60 y = CLAMP(y,
61 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
62 }
63
64 if (ctx->ViewportArray[idx].X == x &&
65 ctx->ViewportArray[idx].Width == width &&
66 ctx->ViewportArray[idx].Y == y &&
67 ctx->ViewportArray[idx].Height == height)
68 return;
69
70 ctx->ViewportArray[idx].X = x;
71 ctx->ViewportArray[idx].Width = width;
72 ctx->ViewportArray[idx].Y = y;
73 ctx->ViewportArray[idx].Height = height;
74 ctx->NewState |= _NEW_VIEWPORT;
75
76 #if 1
77 /* XXX remove this someday. Currently the DRI drivers rely on
78 * the WindowMap matrix being up to date in the driver's Viewport
79 * and DepthRange functions.
80 */
81 _mesa_get_viewport_xform(ctx, idx, scale, translate);
82 _math_matrix_viewport(&ctx->ViewportArray[idx]._WindowMap,
83 scale, translate, ctx->DrawBuffer->_DepthMaxF);
84 #endif
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 /**
97 * Set the viewport.
98 * \sa Called via glViewport() or display list execution.
99 *
100 * Flushes the vertices and calls _mesa_set_viewport() with the given
101 * parameters.
102 */
103 void GLAPIENTRY
104 _mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
105 {
106 unsigned i;
107 GET_CURRENT_CONTEXT(ctx);
108 FLUSH_VERTICES(ctx, 0);
109
110 if (MESA_VERBOSE & VERBOSE_API)
111 _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
112
113 if (width < 0 || height < 0) {
114 _mesa_error(ctx, GL_INVALID_VALUE,
115 "glViewport(%d, %d, %d, %d)", x, y, width, height);
116 return;
117 }
118
119 /* The GL_ARB_viewport_array spec says:
120 *
121 * "Viewport sets the parameters for all viewports to the same values
122 * and is equivalent (assuming no errors are generated) to:
123 *
124 * for (uint i = 0; i < MAX_VIEWPORTS; i++)
125 * ViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);"
126 *
127 * Set all of the viewports supported by the implementation, but only
128 * signal the driver once at the end.
129 */
130 for (i = 0; i < ctx->Const.MaxViewports; i++)
131 set_viewport_no_notify(ctx, i, x, y, width, height);
132
133 if (ctx->Driver.Viewport) {
134 /* Many drivers will use this call to check for window size changes
135 * and reallocate the z/stencil/accum/etc buffers if needed.
136 */
137 ctx->Driver.Viewport(ctx);
138 }
139 }
140
141
142 /**
143 * Set new viewport parameters and update derived state (the _WindowMap
144 * matrix). Usually called from _mesa_Viewport().
145 *
146 * \param ctx GL context.
147 * \param idx Index of the viewport to be updated.
148 * \param x, y coordinates of the lower left corner of the viewport rectangle.
149 * \param width width of the viewport rectangle.
150 * \param height height of the viewport rectangle.
151 */
152 void
153 _mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y,
154 GLfloat width, GLfloat height)
155 {
156 set_viewport_no_notify(ctx, idx, x, y, width, height);
157
158 if (ctx->Driver.Viewport) {
159 /* Many drivers will use this call to check for window size changes
160 * and reallocate the z/stencil/accum/etc buffers if needed.
161 */
162 ctx->Driver.Viewport(ctx);
163 }
164 }
165
166 void GLAPIENTRY
167 _mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat *v)
168 {
169 int i;
170 const struct gl_viewport_inputs *const p = (struct gl_viewport_inputs *) v;
171 GET_CURRENT_CONTEXT(ctx);
172
173 if (MESA_VERBOSE & VERBOSE_API)
174 _mesa_debug(ctx, "glViewportArrayv %d %d\n", first, count);
175
176 if ((first + count) > ctx->Const.MaxViewports) {
177 _mesa_error(ctx, GL_INVALID_VALUE,
178 "glViewportArrayv: first (%d) + count (%d) > MaxViewports "
179 "(%d)",
180 first, count, ctx->Const.MaxViewports);
181 return;
182 }
183
184 /* Verify width & height */
185 for (i = 0; i < count; i++) {
186 if (p[i].Width < 0 || p[i].Height < 0) {
187 _mesa_error(ctx, GL_INVALID_VALUE,
188 "glViewportArrayv: index (%d) width or height < 0 "
189 "(%f, %f)",
190 i + first, p[i].Width, p[i].Height);
191 return;
192 }
193 }
194
195 for (i = 0; i < count; i++)
196 set_viewport_no_notify(ctx, i + first,
197 p[i].X, p[i].Y,
198 p[i].Width, p[i].Height);
199
200 if (ctx->Driver.Viewport)
201 ctx->Driver.Viewport(ctx);
202 }
203
204 static void
205 ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
206 GLfloat w, GLfloat h, const char *function)
207 {
208 GET_CURRENT_CONTEXT(ctx);
209
210 if (MESA_VERBOSE & VERBOSE_API)
211 _mesa_debug(ctx, "%s(%d, %f, %f, %f, %f)\n",
212 function, index, x, y, w, h);
213
214 if (index >= ctx->Const.MaxViewports) {
215 _mesa_error(ctx, GL_INVALID_VALUE,
216 "%s: index (%d) >= MaxViewports (%d)",
217 function, index, ctx->Const.MaxViewports);
218 return;
219 }
220
221 /* Verify width & height */
222 if (w < 0 || h < 0) {
223 _mesa_error(ctx, GL_INVALID_VALUE,
224 "%s: index (%d) width or height < 0 (%f, %f)",
225 function, index, w, h);
226 return;
227 }
228
229 _mesa_set_viewport(ctx, index, x, y, w, h);
230 }
231
232 void GLAPIENTRY
233 _mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
234 GLfloat w, GLfloat h)
235 {
236 ViewportIndexedf(index, x, y, w, h, "glViewportIndexedf");
237 }
238
239 void GLAPIENTRY
240 _mesa_ViewportIndexedfv(GLuint index, const GLfloat *v)
241 {
242 ViewportIndexedf(index, v[0], v[1], v[2], v[3], "glViewportIndexedfv");
243 }
244
245 static void
246 set_depth_range_no_notify(struct gl_context *ctx, unsigned idx,
247 GLclampd nearval, GLclampd farval)
248 {
249 double scale[3], translate[3];
250
251 if (ctx->ViewportArray[idx].Near == nearval &&
252 ctx->ViewportArray[idx].Far == farval)
253 return;
254
255 ctx->ViewportArray[idx].Near = CLAMP(nearval, 0.0, 1.0);
256 ctx->ViewportArray[idx].Far = CLAMP(farval, 0.0, 1.0);
257 ctx->NewState |= _NEW_VIEWPORT;
258
259 #if 1
260 /* XXX remove this someday. Currently the DRI drivers rely on
261 * the WindowMap matrix being up to date in the driver's Viewport
262 * and DepthRange functions.
263 */
264 _mesa_get_viewport_xform(ctx, idx, scale, translate);
265 _math_matrix_viewport(&ctx->ViewportArray[idx]._WindowMap,
266 scale, translate, ctx->DrawBuffer->_DepthMaxF);
267 #endif
268 }
269
270 void
271 _mesa_set_depth_range(struct gl_context *ctx, unsigned idx,
272 GLclampd nearval, GLclampd farval)
273 {
274 set_depth_range_no_notify(ctx, idx, nearval, farval);
275
276 if (ctx->Driver.DepthRange)
277 ctx->Driver.DepthRange(ctx);
278 }
279
280 /**
281 * Called by glDepthRange
282 *
283 * \param nearval specifies the Z buffer value which should correspond to
284 * the near clip plane
285 * \param farval specifies the Z buffer value which should correspond to
286 * the far clip plane
287 */
288 void GLAPIENTRY
289 _mesa_DepthRange(GLclampd nearval, GLclampd farval)
290 {
291 unsigned i;
292 GET_CURRENT_CONTEXT(ctx);
293
294 FLUSH_VERTICES(ctx, 0);
295
296 if (MESA_VERBOSE&VERBOSE_API)
297 _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval);
298
299 /* The GL_ARB_viewport_array spec says:
300 *
301 * "DepthRange sets the depth range for all viewports to the same
302 * values and is equivalent (assuming no errors are generated) to:
303 *
304 * for (uint i = 0; i < MAX_VIEWPORTS; i++)
305 * DepthRangeIndexed(i, n, f);"
306 *
307 * Set the depth range for all of the viewports supported by the
308 * implementation, but only signal the driver once at the end.
309 */
310 for (i = 0; i < ctx->Const.MaxViewports; i++)
311 set_depth_range_no_notify(ctx, i, nearval, farval);
312
313 if (ctx->Driver.DepthRange) {
314 ctx->Driver.DepthRange(ctx);
315 }
316 }
317
318 void GLAPIENTRY
319 _mesa_DepthRangef(GLclampf nearval, GLclampf farval)
320 {
321 _mesa_DepthRange(nearval, farval);
322 }
323
324 /**
325 * Update a range DepthRange values
326 *
327 * \param first starting array index
328 * \param count count of DepthRange items to update
329 * \param v pointer to memory containing
330 * GLclampd near and far clip-plane values
331 */
332 void GLAPIENTRY
333 _mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v)
334 {
335 int i;
336 const struct gl_depthrange_inputs *const p =
337 (struct gl_depthrange_inputs *) v;
338 GET_CURRENT_CONTEXT(ctx);
339
340 if (MESA_VERBOSE & VERBOSE_API)
341 _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count);
342
343 if ((first + count) > ctx->Const.MaxViewports) {
344 _mesa_error(ctx, GL_INVALID_VALUE,
345 "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)",
346 first, count, ctx->Const.MaxViewports);
347 return;
348 }
349
350 for (i = 0; i < count; i++)
351 set_depth_range_no_notify(ctx, i + first, p[i].Near, p[i].Far);
352
353 if (ctx->Driver.DepthRange)
354 ctx->Driver.DepthRange(ctx);
355 }
356
357 /**
358 * Update a single DepthRange
359 *
360 * \param index array index to update
361 * \param nearval specifies the Z buffer value which should correspond to
362 * the near clip plane
363 * \param farval specifies the Z buffer value which should correspond to
364 * the far clip plane
365 */
366 void GLAPIENTRY
367 _mesa_DepthRangeIndexed(GLuint index, GLclampd nearval, GLclampd farval)
368 {
369 GET_CURRENT_CONTEXT(ctx);
370
371 if (MESA_VERBOSE & VERBOSE_API)
372 _mesa_debug(ctx, "glDepthRangeIndexed(%d, %f, %f)\n",
373 index, nearval, farval);
374
375 if (index >= ctx->Const.MaxViewports) {
376 _mesa_error(ctx, GL_INVALID_VALUE,
377 "glDepthRangeIndexed: index (%d) >= MaxViewports (%d)",
378 index, ctx->Const.MaxViewports);
379 return;
380 }
381
382 _mesa_set_depth_range(ctx, index, nearval, farval);
383 }
384
385 /**
386 * Initialize the context viewport attribute group.
387 * \param ctx the GL context.
388 */
389 void _mesa_init_viewport(struct gl_context *ctx)
390 {
391 GLfloat depthMax = 65535.0F; /* sorf of arbitrary */
392 unsigned i;
393
394 ctx->Transform.ClipOrigin = GL_LOWER_LEFT;
395 ctx->Transform.ClipDepthMode = GL_NEGATIVE_ONE_TO_ONE;
396
397 /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
398 * so just initialize all of them.
399 */
400 for (i = 0; i < MAX_VIEWPORTS; i++) {
401 double scale[3], translate[3];
402
403 /* Viewport group */
404 ctx->ViewportArray[i].X = 0;
405 ctx->ViewportArray[i].Y = 0;
406 ctx->ViewportArray[i].Width = 0;
407 ctx->ViewportArray[i].Height = 0;
408 ctx->ViewportArray[i].Near = 0.0;
409 ctx->ViewportArray[i].Far = 1.0;
410 _math_matrix_ctr(&ctx->ViewportArray[i]._WindowMap);
411
412 _mesa_get_viewport_xform(ctx, i, scale, translate);
413 _math_matrix_viewport(&ctx->ViewportArray[i]._WindowMap,
414 scale, translate, depthMax);
415 }
416 }
417
418
419 /**
420 * Free the context viewport attribute group data.
421 * \param ctx the GL context.
422 */
423 void _mesa_free_viewport_data(struct gl_context *ctx)
424 {
425 unsigned i;
426
427 for (i = 0; i < MAX_VIEWPORTS; i++)
428 _math_matrix_dtr(&ctx->ViewportArray[i]._WindowMap);
429 }
430
431 extern void GLAPIENTRY
432 _mesa_ClipControl(GLenum origin, GLenum depth)
433 {
434 GET_CURRENT_CONTEXT(ctx);
435
436 if (MESA_VERBOSE&VERBOSE_API)
437 _mesa_debug(ctx, "glClipControl(%s, %s)\n",
438 _mesa_lookup_enum_by_nr(origin),
439 _mesa_lookup_enum_by_nr(depth));
440
441 ASSERT_OUTSIDE_BEGIN_END(ctx);
442
443 if (!ctx->Extensions.ARB_clip_control) {
444 _mesa_error(ctx, GL_INVALID_OPERATION, "glClipControl");
445 return;
446 }
447
448 if (origin != GL_LOWER_LEFT && origin != GL_UPPER_LEFT) {
449 _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
450 return;
451 }
452
453 if (depth != GL_NEGATIVE_ONE_TO_ONE && depth != GL_ZERO_TO_ONE) {
454 _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
455 return;
456 }
457
458 if (ctx->Transform.ClipOrigin == origin &&
459 ctx->Transform.ClipDepthMode == depth)
460 return;
461
462 /* Affects transform state and the viewport transform */
463 FLUSH_VERTICES(ctx, _NEW_TRANSFORM | _NEW_VIEWPORT);
464
465 if (ctx->Transform.ClipOrigin != origin) {
466 ctx->Transform.ClipOrigin = origin;
467
468 /* Affects the winding order of the front face. */
469 ctx->NewState |= _NEW_POLYGON;
470
471 if (ctx->Driver.FrontFace)
472 ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
473 }
474
475 if (ctx->Transform.ClipDepthMode != depth) {
476 ctx->Transform.ClipDepthMode = depth;
477
478 if (ctx->Driver.DepthRange)
479 ctx->Driver.DepthRange(ctx);
480 }
481 }
482
483 /**
484 * Computes the scaling and the translation part of the
485 * viewport transform matrix of the \param i-th viewport
486 * and writes that into \param scale and \param translate.
487 */
488 void
489 _mesa_get_viewport_xform(struct gl_context *ctx, unsigned i,
490 double scale[3], double translate[3])
491 {
492 double x = ctx->ViewportArray[i].X;
493 double y = ctx->ViewportArray[i].Y;
494 double half_width = 0.5*ctx->ViewportArray[i].Width;
495 double half_height = 0.5*ctx->ViewportArray[i].Height;
496 double n = ctx->ViewportArray[i].Near;
497 double f = ctx->ViewportArray[i].Far;
498
499 scale[0] = half_width;
500 translate[0] = half_width + x;
501 if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) {
502 scale[1] = -half_height;
503 translate[1] = half_height - y;
504 } else {
505 scale[1] = half_height;
506 translate[1] = half_height + y;
507 }
508 if (ctx->Transform.ClipDepthMode == GL_NEGATIVE_ONE_TO_ONE) {
509 scale[2] = 0.5*(f - n);
510 translate[2] = 0.5*(n + f);
511 } else {
512 scale[2] = f - n;
513 translate[2] = n;
514 }
515 }