1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2007 Brian Paul 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#include "main/glheader.h" 27#include "main/context.h" 28#include "main/enums.h" 29#include "main/mtypes.h" 30#include "main/scissor.h" 31#include "api_exec_decl.h" 32 33#include "state_tracker/st_cb_bitmap.h" 34#include "state_tracker/st_context.h" 35 36/** 37 * Set scissor rectangle data directly in ScissorArray 38 * 39 * This is an internal function that performs no error checking on the 40 * supplied data. It also does \b not call \c dd_function_table::Scissor. 41 * 42 * \sa _mesa_set_scissor 43 */ 44static void 45set_scissor_no_notify(struct gl_context *ctx, unsigned idx, 46 GLint x, GLint y, GLsizei width, GLsizei height) 47{ 48 if (x == ctx->Scissor.ScissorArray[idx].X && 49 y == ctx->Scissor.ScissorArray[idx].Y && 50 width == ctx->Scissor.ScissorArray[idx].Width && 51 height == ctx->Scissor.ScissorArray[idx].Height) 52 return; 53 54 if (ctx->Scissor.EnableFlags) 55 st_flush_bitmap_cache(st_context(ctx)); 56 57 FLUSH_VERTICES(ctx, 0, GL_SCISSOR_BIT); 58 ctx->NewDriverState |= ST_NEW_SCISSOR; 59 60 ctx->Scissor.ScissorArray[idx].X = x; 61 ctx->Scissor.ScissorArray[idx].Y = y; 62 ctx->Scissor.ScissorArray[idx].Width = width; 63 ctx->Scissor.ScissorArray[idx].Height = height; 64} 65 66static void 67scissor(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height) 68{ 69 unsigned i; 70 71 /* The GL_ARB_viewport_array spec says: 72 * 73 * "Scissor sets the scissor rectangle for all viewports to the same 74 * values and is equivalent (assuming no errors are generated) to: 75 * 76 * for (uint i = 0; i < MAX_VIEWPORTS; i++) { 77 * ScissorIndexed(i, left, bottom, width, height); 78 * }" 79 * 80 * Set the scissor rectangle for all of the viewports supported by the 81 * implementation, but only signal the driver once at the end. 82 */ 83 for (i = 0; i < ctx->Const.MaxViewports; i++) 84 set_scissor_no_notify(ctx, i, x, y, width, height); 85} 86 87/** 88 * Called via glScissor 89 */ 90void GLAPIENTRY 91_mesa_Scissor_no_error(GLint x, GLint y, GLsizei width, GLsizei height) 92{ 93 GET_CURRENT_CONTEXT(ctx); 94 scissor(ctx, x, y, width, height); 95} 96 97void GLAPIENTRY 98_mesa_Scissor(GLint x, GLint y, GLsizei width, GLsizei height) 99{ 100 GET_CURRENT_CONTEXT(ctx); 101 102 if (MESA_VERBOSE & VERBOSE_API) 103 _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height); 104 105 if (width < 0 || height < 0) { 106 _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" ); 107 return; 108 } 109 110 scissor(ctx, x, y, width, height); 111} 112 113 114/** 115 * Define the scissor box. 116 * 117 * \param x, y coordinates of the scissor box lower-left corner. 118 * \param width width of the scissor box. 119 * \param height height of the scissor box. 120 * 121 * \sa glScissor(). 122 * 123 * Verifies the parameters and updates __struct gl_contextRec::Scissor. On a 124 * change flushes the vertices and notifies the driver via 125 * the dd_function_table::Scissor callback. 126 */ 127void 128_mesa_set_scissor(struct gl_context *ctx, unsigned idx, 129 GLint x, GLint y, GLsizei width, GLsizei height) 130{ 131 set_scissor_no_notify(ctx, idx, x, y, width, height); 132} 133 134static void 135scissor_array(struct gl_context *ctx, GLuint first, GLsizei count, 136 struct gl_scissor_rect *rect) 137{ 138 for (GLsizei i = 0; i < count; i++) { 139 set_scissor_no_notify(ctx, i + first, rect[i].X, rect[i].Y, 140 rect[i].Width, rect[i].Height); 141 } 142} 143 144/** 145 * Define count scissor boxes starting at index. 146 * 147 * \param index index of first scissor records to set 148 * \param count number of scissor records to set 149 * \param x, y pointer to array of struct gl_scissor_rects 150 * 151 * \sa glScissorArrayv(). 152 * 153 * Verifies the parameters and call set_scissor_no_notify to do the work. 154 */ 155void GLAPIENTRY 156_mesa_ScissorArrayv_no_error(GLuint first, GLsizei count, const GLint *v) 157{ 158 GET_CURRENT_CONTEXT(ctx); 159 160 struct gl_scissor_rect *p = (struct gl_scissor_rect *)v; 161 scissor_array(ctx, first, count, p); 162} 163 164void GLAPIENTRY 165_mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v) 166{ 167 int i; 168 struct gl_scissor_rect *p = (struct gl_scissor_rect *) v; 169 GET_CURRENT_CONTEXT(ctx); 170 171 if ((first + count) > ctx->Const.MaxViewports) { 172 _mesa_error(ctx, GL_INVALID_VALUE, 173 "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)", 174 first, count, ctx->Const.MaxViewports); 175 return; 176 } 177 178 /* Verify width & height */ 179 for (i = 0; i < count; i++) { 180 if (p[i].Width < 0 || p[i].Height < 0) { 181 _mesa_error(ctx, GL_INVALID_VALUE, 182 "glScissorArrayv: index (%d) width or height < 0 (%d, %d)", 183 i, p[i].Width, p[i].Height); 184 return; 185 } 186 } 187 188 scissor_array(ctx, first, count, p); 189} 190 191/** 192 * Define the scissor box. 193 * 194 * \param index index of scissor records to set 195 * \param x, y coordinates of the scissor box lower-left corner. 196 * \param width width of the scissor box. 197 * \param height height of the scissor box. 198 * 199 * Verifies the parameters call set_scissor_no_notify to do the work. 200 */ 201static void 202scissor_indexed_err(struct gl_context *ctx, GLuint index, GLint left, 203 GLint bottom, GLsizei width, GLsizei height, 204 const char *function) 205{ 206 if (MESA_VERBOSE & VERBOSE_API) 207 _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n", 208 function, index, left, bottom, width, height); 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 if (width < 0 || height < 0) { 218 _mesa_error(ctx, GL_INVALID_VALUE, 219 "%s: index (%d) width or height < 0 (%d, %d)", 220 function, index, width, height); 221 return; 222 } 223 224 _mesa_set_scissor(ctx, index, left, bottom, width, height); 225} 226 227void GLAPIENTRY 228_mesa_ScissorIndexed_no_error(GLuint index, GLint left, GLint bottom, 229 GLsizei width, GLsizei height) 230{ 231 GET_CURRENT_CONTEXT(ctx); 232 _mesa_set_scissor(ctx, index, left, bottom, width, height); 233} 234 235void GLAPIENTRY 236_mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom, 237 GLsizei width, GLsizei height) 238{ 239 GET_CURRENT_CONTEXT(ctx); 240 scissor_indexed_err(ctx, index, left, bottom, width, height, 241 "glScissorIndexed"); 242} 243 244void GLAPIENTRY 245_mesa_ScissorIndexedv_no_error(GLuint index, const GLint *v) 246{ 247 GET_CURRENT_CONTEXT(ctx); 248 _mesa_set_scissor(ctx, index, v[0], v[1], v[2], v[3]); 249} 250 251void GLAPIENTRY 252_mesa_ScissorIndexedv(GLuint index, const GLint *v) 253{ 254 GET_CURRENT_CONTEXT(ctx); 255 scissor_indexed_err(ctx, index, v[0], v[1], v[2], v[3], 256 "glScissorIndexedv"); 257} 258 259void GLAPIENTRY 260_mesa_WindowRectanglesEXT(GLenum mode, GLsizei count, const GLint *box) 261{ 262 int i; 263 struct gl_scissor_rect newval[MAX_WINDOW_RECTANGLES]; 264 GET_CURRENT_CONTEXT(ctx); 265 266 if (MESA_VERBOSE & VERBOSE_API) 267 _mesa_debug(ctx, "glWindowRectanglesEXT(%s, %d, %p)\n", 268 _mesa_enum_to_string(mode), count, box); 269 270 if (mode != GL_INCLUSIVE_EXT && mode != GL_EXCLUSIVE_EXT) { 271 _mesa_error(ctx, GL_INVALID_ENUM, 272 "glWindowRectanglesEXT(invalid mode 0x%x)", mode); 273 return; 274 } 275 276 if (count < 0) { 277 _mesa_error(ctx, GL_INVALID_VALUE, "glWindowRectanglesEXT(count < 0)"); 278 return; 279 } 280 281 if (count > ctx->Const.MaxWindowRectangles) { 282 _mesa_error(ctx, GL_INVALID_VALUE, 283 "glWindowRectanglesEXT(count >= MaxWindowRectangles (%d)", 284 ctx->Const.MaxWindowRectangles); 285 return; 286 } 287 288 for (i = 0; i < count; i++) { 289 if (box[2] < 0 || box[3] < 0) { 290 _mesa_error(ctx, GL_INVALID_VALUE, 291 "glWindowRectanglesEXT(box %d: w < 0 || h < 0)", i); 292 return; 293 } 294 newval[i].X = box[0]; 295 newval[i].Y = box[1]; 296 newval[i].Width = box[2]; 297 newval[i].Height = box[3]; 298 box += 4; 299 } 300 301 st_flush_bitmap_cache(st_context(ctx)); 302 303 FLUSH_VERTICES(ctx, 0, GL_SCISSOR_BIT); 304 ctx->NewDriverState |= ST_NEW_WINDOW_RECTANGLES; 305 306 memcpy(ctx->Scissor.WindowRects, newval, 307 sizeof(struct gl_scissor_rect) * count); 308 ctx->Scissor.NumWindowRects = count; 309 ctx->Scissor.WindowRectMode = mode; 310} 311 312 313/** 314 * Initialize the context's scissor state. 315 * \param ctx the GL context. 316 */ 317void 318_mesa_init_scissor(struct gl_context *ctx) 319{ 320 unsigned i; 321 322 /* Scissor group */ 323 ctx->Scissor.EnableFlags = 0; 324 ctx->Scissor.WindowRectMode = GL_EXCLUSIVE_EXT; 325 326 /* Note: ctx->Const.MaxViewports may not have been set by the driver yet, 327 * so just initialize all of them. 328 */ 329 for (i = 0; i < MAX_VIEWPORTS; i++) 330 set_scissor_no_notify(ctx, i, 0, 0, 0, 0); 331} 332