viewport.c revision 848b8605
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 "macros.h" 34#include "mtypes.h" 35#include "viewport.h" 36 37static void 38set_viewport_no_notify(struct gl_context *ctx, unsigned idx, 39 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 (ctx->Extensions.ARB_viewport_array) { 55 x = CLAMP(x, 56 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max); 57 y = CLAMP(y, 58 ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max); 59 } 60 61 ctx->ViewportArray[idx].X = x; 62 ctx->ViewportArray[idx].Width = width; 63 ctx->ViewportArray[idx].Y = y; 64 ctx->ViewportArray[idx].Height = height; 65 ctx->NewState |= _NEW_VIEWPORT; 66 67#if 1 68 /* XXX remove this someday. Currently the DRI drivers rely on 69 * the WindowMap matrix being up to date in the driver's Viewport 70 * and DepthRange functions. 71 */ 72 _math_matrix_viewport(&ctx->ViewportArray[idx]._WindowMap, 73 ctx->ViewportArray[idx].X, 74 ctx->ViewportArray[idx].Y, 75 ctx->ViewportArray[idx].Width, 76 ctx->ViewportArray[idx].Height, 77 ctx->ViewportArray[idx].Near, 78 ctx->ViewportArray[idx].Far, 79 ctx->DrawBuffer->_DepthMaxF); 80#endif 81} 82 83struct gl_viewport_inputs { 84 GLfloat X, Y; /**< position */ 85 GLfloat Width, Height; /**< size */ 86}; 87 88struct gl_depthrange_inputs { 89 GLdouble Near, Far; /**< Depth buffer range */ 90}; 91 92/** 93 * Set the viewport. 94 * \sa Called via glViewport() or display list execution. 95 * 96 * Flushes the vertices and calls _mesa_set_viewport() with the given 97 * parameters. 98 */ 99void GLAPIENTRY 100_mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height) 101{ 102 unsigned i; 103 GET_CURRENT_CONTEXT(ctx); 104 FLUSH_VERTICES(ctx, 0); 105 106 if (MESA_VERBOSE & VERBOSE_API) 107 _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height); 108 109 if (width < 0 || height < 0) { 110 _mesa_error(ctx, GL_INVALID_VALUE, 111 "glViewport(%d, %d, %d, %d)", x, y, width, height); 112 return; 113 } 114 115 /* The GL_ARB_viewport_array spec says: 116 * 117 * "Viewport sets the parameters for all viewports to the same values 118 * and is equivalent (assuming no errors are generated) to: 119 * 120 * for (uint i = 0; i < MAX_VIEWPORTS; i++) 121 * ViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);" 122 * 123 * Set all of the viewports supported by the implementation, but only 124 * signal the driver once at the end. 125 */ 126 for (i = 0; i < ctx->Const.MaxViewports; i++) 127 set_viewport_no_notify(ctx, i, x, y, width, height); 128 129 if (ctx->Driver.Viewport) { 130 /* Many drivers will use this call to check for window size changes 131 * and reallocate the z/stencil/accum/etc buffers if needed. 132 */ 133 ctx->Driver.Viewport(ctx); 134 } 135} 136 137 138/** 139 * Set new viewport parameters and update derived state (the _WindowMap 140 * matrix). Usually called from _mesa_Viewport(). 141 * 142 * \param ctx GL context. 143 * \param idx Index of the viewport to be updated. 144 * \param x, y coordinates of the lower left corner of the viewport rectangle. 145 * \param width width of the viewport rectangle. 146 * \param height height of the viewport rectangle. 147 */ 148void 149_mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y, 150 GLfloat width, GLfloat height) 151{ 152 set_viewport_no_notify(ctx, idx, x, y, width, height); 153 154 if (ctx->Driver.Viewport) { 155 /* Many drivers will use this call to check for window size changes 156 * and reallocate the z/stencil/accum/etc buffers if needed. 157 */ 158 ctx->Driver.Viewport(ctx); 159 } 160} 161 162void GLAPIENTRY 163_mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat *v) 164{ 165 int i; 166 const struct gl_viewport_inputs *const p = (struct gl_viewport_inputs *) v; 167 GET_CURRENT_CONTEXT(ctx); 168 169 if (MESA_VERBOSE & VERBOSE_API) 170 _mesa_debug(ctx, "glViewportArrayv %d %d\n", first, count); 171 172 if ((first + count) > ctx->Const.MaxViewports) { 173 _mesa_error(ctx, GL_INVALID_VALUE, 174 "glViewportArrayv: first (%d) + count (%d) > MaxViewports " 175 "(%d)", 176 first, count, ctx->Const.MaxViewports); 177 return; 178 } 179 180 /* Verify width & height */ 181 for (i = 0; i < count; i++) { 182 if (p[i].Width < 0 || p[i].Height < 0) { 183 _mesa_error(ctx, GL_INVALID_VALUE, 184 "glViewportArrayv: index (%d) width or height < 0 " 185 "(%f, %f)", 186 i + first, p[i].Width, p[i].Height); 187 return; 188 } 189 } 190 191 for (i = 0; i < count; i++) 192 set_viewport_no_notify(ctx, i + first, 193 p[i].X, p[i].Y, 194 p[i].Width, p[i].Height); 195 196 if (ctx->Driver.Viewport) 197 ctx->Driver.Viewport(ctx); 198} 199 200static void 201ViewportIndexedf(GLuint index, GLfloat x, GLfloat y, 202 GLfloat w, GLfloat h, const char *function) 203{ 204 GET_CURRENT_CONTEXT(ctx); 205 206 if (MESA_VERBOSE & VERBOSE_API) 207 _mesa_debug(ctx, "%s(%d, %f, %f, %f, %f)\n", 208 function, index, x, y, w, h); 209 210 if (index >= ctx->Const.MaxViewports) { 211 _mesa_error(ctx, GL_INVALID_VALUE, 212 "%s: index (%d) >= MaxViewports (%d)", 213 function, index, ctx->Const.MaxViewports); 214 return; 215 } 216 217 /* Verify width & height */ 218 if (w < 0 || h < 0) { 219 _mesa_error(ctx, GL_INVALID_VALUE, 220 "%s: index (%d) width or height < 0 (%f, %f)", 221 function, index, w, h); 222 return; 223 } 224 225 _mesa_set_viewport(ctx, index, x, y, w, h); 226} 227 228void GLAPIENTRY 229_mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y, 230 GLfloat w, GLfloat h) 231{ 232 ViewportIndexedf(index, x, y, w, h, "glViewportIndexedf"); 233} 234 235void GLAPIENTRY 236_mesa_ViewportIndexedfv(GLuint index, const GLfloat *v) 237{ 238 ViewportIndexedf(index, v[0], v[1], v[2], v[3], "glViewportIndexedfv"); 239} 240 241static void 242set_depth_range_no_notify(struct gl_context *ctx, unsigned idx, 243 GLclampd nearval, GLclampd farval) 244{ 245 if (ctx->ViewportArray[idx].Near == nearval && 246 ctx->ViewportArray[idx].Far == farval) 247 return; 248 249 ctx->ViewportArray[idx].Near = CLAMP(nearval, 0.0, 1.0); 250 ctx->ViewportArray[idx].Far = CLAMP(farval, 0.0, 1.0); 251 ctx->NewState |= _NEW_VIEWPORT; 252 253#if 1 254 /* XXX remove this someday. Currently the DRI drivers rely on 255 * the WindowMap matrix being up to date in the driver's Viewport 256 * and DepthRange functions. 257 */ 258 _math_matrix_viewport(&ctx->ViewportArray[idx]._WindowMap, 259 ctx->ViewportArray[idx].X, 260 ctx->ViewportArray[idx].Y, 261 ctx->ViewportArray[idx].Width, 262 ctx->ViewportArray[idx].Height, 263 ctx->ViewportArray[idx].Near, 264 ctx->ViewportArray[idx].Far, 265 ctx->DrawBuffer->_DepthMaxF); 266#endif 267} 268 269void 270_mesa_set_depth_range(struct gl_context *ctx, unsigned idx, 271 GLclampd nearval, GLclampd farval) 272{ 273 set_depth_range_no_notify(ctx, idx, nearval, farval); 274 275 if (ctx->Driver.DepthRange) 276 ctx->Driver.DepthRange(ctx); 277} 278 279/** 280 * Called by glDepthRange 281 * 282 * \param nearval specifies the Z buffer value which should correspond to 283 * the near clip plane 284 * \param farval specifies the Z buffer value which should correspond to 285 * the far clip plane 286 */ 287void GLAPIENTRY 288_mesa_DepthRange(GLclampd nearval, GLclampd farval) 289{ 290 unsigned i; 291 GET_CURRENT_CONTEXT(ctx); 292 293 FLUSH_VERTICES(ctx, 0); 294 295 if (MESA_VERBOSE&VERBOSE_API) 296 _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval); 297 298 /* The GL_ARB_viewport_array spec says: 299 * 300 * "DepthRange sets the depth range for all viewports to the same 301 * values and is equivalent (assuming no errors are generated) to: 302 * 303 * for (uint i = 0; i < MAX_VIEWPORTS; i++) 304 * DepthRangeIndexed(i, n, f);" 305 * 306 * Set the depth range for all of the viewports supported by the 307 * implementation, but only signal the driver once at the end. 308 */ 309 for (i = 0; i < ctx->Const.MaxViewports; i++) 310 set_depth_range_no_notify(ctx, i, nearval, farval); 311 312 if (ctx->Driver.DepthRange) { 313 ctx->Driver.DepthRange(ctx); 314 } 315} 316 317void GLAPIENTRY 318_mesa_DepthRangef(GLclampf nearval, GLclampf farval) 319{ 320 _mesa_DepthRange(nearval, farval); 321} 322 323/** 324 * Update a range DepthRange values 325 * 326 * \param first starting array index 327 * \param count count of DepthRange items to update 328 * \param v pointer to memory containing 329 * GLclampd near and far clip-plane values 330 */ 331void GLAPIENTRY 332_mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v) 333{ 334 int i; 335 const struct gl_depthrange_inputs *const p = 336 (struct gl_depthrange_inputs *) v; 337 GET_CURRENT_CONTEXT(ctx); 338 339 if (MESA_VERBOSE & VERBOSE_API) 340 _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count); 341 342 if ((first + count) > ctx->Const.MaxViewports) { 343 _mesa_error(ctx, GL_INVALID_VALUE, 344 "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)", 345 first, count, ctx->Const.MaxViewports); 346 return; 347 } 348 349 for (i = 0; i < count; i++) 350 set_depth_range_no_notify(ctx, i + first, p[i].Near, p[i].Far); 351 352 if (ctx->Driver.DepthRange) 353 ctx->Driver.DepthRange(ctx); 354} 355 356/** 357 * Update a single DepthRange 358 * 359 * \param index array index to update 360 * \param nearval specifies the Z buffer value which should correspond to 361 * the near clip plane 362 * \param farval specifies the Z buffer value which should correspond to 363 * the far clip plane 364 */ 365void GLAPIENTRY 366_mesa_DepthRangeIndexed(GLuint index, GLclampd nearval, GLclampd farval) 367{ 368 GET_CURRENT_CONTEXT(ctx); 369 370 if (MESA_VERBOSE & VERBOSE_API) 371 _mesa_debug(ctx, "glDepthRangeIndexed(%d, %f, %f)\n", 372 index, nearval, farval); 373 374 if (index >= ctx->Const.MaxViewports) { 375 _mesa_error(ctx, GL_INVALID_VALUE, 376 "glDepthRangeIndexed: index (%d) >= MaxViewports (%d)", 377 index, ctx->Const.MaxViewports); 378 return; 379 } 380 381 _mesa_set_depth_range(ctx, index, nearval, farval); 382} 383 384/** 385 * Initialize the context viewport attribute group. 386 * \param ctx the GL context. 387 */ 388void _mesa_init_viewport(struct gl_context *ctx) 389{ 390 GLfloat depthMax = 65535.0F; /* sorf of arbitrary */ 391 unsigned i; 392 393 /* Note: ctx->Const.MaxViewports may not have been set by the driver yet, 394 * so just initialize all of them. 395 */ 396 for (i = 0; i < MAX_VIEWPORTS; i++) { 397 /* Viewport group */ 398 ctx->ViewportArray[i].X = 0; 399 ctx->ViewportArray[i].Y = 0; 400 ctx->ViewportArray[i].Width = 0; 401 ctx->ViewportArray[i].Height = 0; 402 ctx->ViewportArray[i].Near = 0.0; 403 ctx->ViewportArray[i].Far = 1.0; 404 _math_matrix_ctr(&ctx->ViewportArray[i]._WindowMap); 405 406 _math_matrix_viewport(&ctx->ViewportArray[i]._WindowMap, 0, 0, 0, 0, 407 0.0F, 1.0F, depthMax); 408 } 409} 410 411 412/** 413 * Free the context viewport attribute group data. 414 * \param ctx the GL context. 415 */ 416void _mesa_free_viewport_data(struct gl_context *ctx) 417{ 418 unsigned i; 419 420 for (i = 0; i < MAX_VIEWPORTS; i++) 421 _math_matrix_dtr(&ctx->ViewportArray[i]._WindowMap); 422} 423 424