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