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