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