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