• 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 #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  */
44 static void
set_scissor_no_notify(struct gl_context * ctx,unsigned idx,GLint x,GLint y,GLsizei width,GLsizei height)45 set_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 
66 static void
scissor(struct gl_context * ctx,GLint x,GLint y,GLsizei width,GLsizei height)67 scissor(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  */
90 void GLAPIENTRY
_mesa_Scissor_no_error(GLint x,GLint y,GLsizei width,GLsizei height)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 
97 void GLAPIENTRY
_mesa_Scissor(GLint x,GLint y,GLsizei width,GLsizei height)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  */
127 void
_mesa_set_scissor(struct gl_context * ctx,unsigned idx,GLint x,GLint y,GLsizei width,GLsizei height)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 
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 
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  */
155 void GLAPIENTRY
_mesa_ScissorArrayv_no_error(GLuint first,GLsizei count,const GLint * v)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 
164 void GLAPIENTRY
_mesa_ScissorArrayv(GLuint first,GLsizei count,const GLint * v)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  */
201 static void
scissor_indexed_err(struct gl_context * ctx,GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height,const char * function)202 scissor_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 
227 void GLAPIENTRY
_mesa_ScissorIndexed_no_error(GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height)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 
235 void GLAPIENTRY
_mesa_ScissorIndexed(GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height)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 
244 void GLAPIENTRY
_mesa_ScissorIndexedv_no_error(GLuint index,const GLint * v)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 
251 void GLAPIENTRY
_mesa_ScissorIndexedv(GLuint index,const GLint * v)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 
259 void GLAPIENTRY
_mesa_WindowRectanglesEXT(GLenum mode,GLsizei count,const GLint * box)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  */
317 void
_mesa_init_scissor(struct gl_context * ctx)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