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