xref: /aosp_15_r20/external/mesa3d/src/mesa/main/scissor.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 "util/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    FLUSH_VERTICES(ctx, 0, GL_SCISSOR_BIT);
55    ctx->NewDriverState |= ST_NEW_SCISSOR;
56 
57    ctx->Scissor.ScissorArray[idx].X = x;
58    ctx->Scissor.ScissorArray[idx].Y = y;
59    ctx->Scissor.ScissorArray[idx].Width = width;
60    ctx->Scissor.ScissorArray[idx].Height = height;
61 }
62 
63 static void
scissor(struct gl_context * ctx,GLint x,GLint y,GLsizei width,GLsizei height)64 scissor(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height)
65 {
66    unsigned i;
67 
68    /* The GL_ARB_viewport_array spec says:
69     *
70     *     "Scissor sets the scissor rectangle for all viewports to the same
71     *     values and is equivalent (assuming no errors are generated) to:
72     *
73     *     for (uint i = 0; i < MAX_VIEWPORTS; i++) {
74     *         ScissorIndexed(i, left, bottom, width, height);
75     *     }"
76     *
77     * Set the scissor rectangle for all of the viewports supported by the
78     * implementation, but only signal the driver once at the end.
79     */
80    for (i = 0; i < ctx->Const.MaxViewports; i++)
81       set_scissor_no_notify(ctx, i, x, y, width, height);
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 
131 static void
scissor_array(struct gl_context * ctx,GLuint first,GLsizei count,struct gl_scissor_rect * rect)132 scissor_array(struct gl_context *ctx, GLuint first, GLsizei count,
133               struct gl_scissor_rect *rect)
134 {
135    for (GLsizei i = 0; i < count; i++) {
136       set_scissor_no_notify(ctx, i + first, rect[i].X, rect[i].Y,
137                             rect[i].Width, rect[i].Height);
138    }
139 }
140 
141 /**
142  * Define count scissor boxes starting at index.
143  *
144  * \param index  index of first scissor records to set
145  * \param count  number of scissor records to set
146  * \param x, y   pointer to array of struct gl_scissor_rects
147  *
148  * \sa glScissorArrayv().
149  *
150  * Verifies the parameters and call set_scissor_no_notify to do the work.
151  */
152 void GLAPIENTRY
_mesa_ScissorArrayv_no_error(GLuint first,GLsizei count,const GLint * v)153 _mesa_ScissorArrayv_no_error(GLuint first, GLsizei count, const GLint *v)
154 {
155    GET_CURRENT_CONTEXT(ctx);
156 
157    struct gl_scissor_rect *p = (struct gl_scissor_rect *)v;
158    scissor_array(ctx, first, count, p);
159 }
160 
161 void GLAPIENTRY
_mesa_ScissorArrayv(GLuint first,GLsizei count,const GLint * v)162 _mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v)
163 {
164    int i;
165    struct gl_scissor_rect *p = (struct gl_scissor_rect *) v;
166    GET_CURRENT_CONTEXT(ctx);
167 
168    if ((first + count) > ctx->Const.MaxViewports) {
169       _mesa_error(ctx, GL_INVALID_VALUE,
170                   "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)",
171                   first, count, ctx->Const.MaxViewports);
172       return;
173    }
174 
175    /* Verify width & height */
176    for (i = 0; i < count; i++) {
177       if (p[i].Width < 0 || p[i].Height < 0) {
178          _mesa_error(ctx, GL_INVALID_VALUE,
179                      "glScissorArrayv: index (%d) width or height < 0 (%d, %d)",
180                      i, p[i].Width, p[i].Height);
181          return;
182       }
183    }
184 
185    scissor_array(ctx, first, count, p);
186 }
187 
188 /**
189  * Define the scissor box.
190  *
191  * \param index  index of scissor records to set
192  * \param x, y   coordinates of the scissor box lower-left corner.
193  * \param width  width of the scissor box.
194  * \param height height of the scissor box.
195  *
196  * Verifies the parameters call set_scissor_no_notify to do the work.
197  */
198 static void
scissor_indexed_err(struct gl_context * ctx,GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height,const char * function)199 scissor_indexed_err(struct gl_context *ctx, GLuint index, GLint left,
200                     GLint bottom, GLsizei width, GLsizei height,
201                     const char *function)
202 {
203    if (MESA_VERBOSE & VERBOSE_API)
204       _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n",
205                   function, index, left, bottom, width, height);
206 
207    if (index >= ctx->Const.MaxViewports) {
208       _mesa_error(ctx, GL_INVALID_VALUE,
209                   "%s: index (%d) >= MaxViewports (%d)",
210                   function, index, ctx->Const.MaxViewports);
211       return;
212    }
213 
214    if (width < 0 || height < 0) {
215       _mesa_error(ctx, GL_INVALID_VALUE,
216                   "%s: index (%d) width or height < 0 (%d, %d)",
217                   function, index, width, height);
218       return;
219    }
220 
221    _mesa_set_scissor(ctx, index, left, bottom, width, height);
222 }
223 
224 void GLAPIENTRY
_mesa_ScissorIndexed_no_error(GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height)225 _mesa_ScissorIndexed_no_error(GLuint index, GLint left, GLint bottom,
226                               GLsizei width, GLsizei height)
227 {
228    GET_CURRENT_CONTEXT(ctx);
229    _mesa_set_scissor(ctx, index, left, bottom, width, height);
230 }
231 
232 void GLAPIENTRY
_mesa_ScissorIndexed(GLuint index,GLint left,GLint bottom,GLsizei width,GLsizei height)233 _mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom,
234                      GLsizei width, GLsizei height)
235 {
236    GET_CURRENT_CONTEXT(ctx);
237    scissor_indexed_err(ctx, index, left, bottom, width, height,
238                        "glScissorIndexed");
239 }
240 
241 void GLAPIENTRY
_mesa_ScissorIndexedv_no_error(GLuint index,const GLint * v)242 _mesa_ScissorIndexedv_no_error(GLuint index, const GLint *v)
243 {
244    GET_CURRENT_CONTEXT(ctx);
245    _mesa_set_scissor(ctx, index, v[0], v[1], v[2], v[3]);
246 }
247 
248 void GLAPIENTRY
_mesa_ScissorIndexedv(GLuint index,const GLint * v)249 _mesa_ScissorIndexedv(GLuint index, const GLint *v)
250 {
251    GET_CURRENT_CONTEXT(ctx);
252    scissor_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
253                        "glScissorIndexedv");
254 }
255 
256 void GLAPIENTRY
_mesa_WindowRectanglesEXT(GLenum mode,GLsizei count,const GLint * box)257 _mesa_WindowRectanglesEXT(GLenum mode, GLsizei count, const GLint *box)
258 {
259    int i;
260    struct gl_scissor_rect newval[MAX_WINDOW_RECTANGLES];
261    GET_CURRENT_CONTEXT(ctx);
262 
263    if (MESA_VERBOSE & VERBOSE_API)
264       _mesa_debug(ctx, "glWindowRectanglesEXT(%s, %d, %p)\n",
265                   _mesa_enum_to_string(mode), count, box);
266 
267    if (mode != GL_INCLUSIVE_EXT && mode != GL_EXCLUSIVE_EXT) {
268       _mesa_error(ctx, GL_INVALID_ENUM,
269                   "glWindowRectanglesEXT(invalid mode 0x%x)", mode);
270       return;
271    }
272 
273    if (count < 0) {
274       _mesa_error(ctx, GL_INVALID_VALUE, "glWindowRectanglesEXT(count < 0)");
275       return;
276    }
277 
278    if (count > ctx->Const.MaxWindowRectangles) {
279       _mesa_error(ctx, GL_INVALID_VALUE,
280                   "glWindowRectanglesEXT(count >= MaxWindowRectangles (%d)",
281                   ctx->Const.MaxWindowRectangles);
282       return;
283    }
284 
285    for (i = 0; i < count; i++) {
286       if (box[2] < 0 || box[3] < 0) {
287          _mesa_error(ctx, GL_INVALID_VALUE,
288                      "glWindowRectanglesEXT(box %d: w < 0 || h < 0)", i);
289          return;
290       }
291       newval[i].X = box[0];
292       newval[i].Y = box[1];
293       newval[i].Width = box[2];
294       newval[i].Height = box[3];
295       box += 4;
296    }
297 
298    st_flush_bitmap_cache(st_context(ctx));
299 
300    FLUSH_VERTICES(ctx, 0, GL_SCISSOR_BIT);
301    ctx->NewDriverState |= ST_NEW_WINDOW_RECTANGLES;
302 
303    memcpy(ctx->Scissor.WindowRects, newval,
304           sizeof(struct gl_scissor_rect) * count);
305    ctx->Scissor.NumWindowRects = count;
306    ctx->Scissor.WindowRectMode = mode;
307 }
308 
309 
310 /**
311  * Initialize the context's scissor state.
312  * \param ctx  the GL context.
313  */
314 void
_mesa_init_scissor(struct gl_context * ctx)315 _mesa_init_scissor(struct gl_context *ctx)
316 {
317    unsigned i;
318 
319    /* Scissor group */
320    ctx->Scissor.EnableFlags = 0;
321    ctx->Scissor.WindowRectMode = GL_EXCLUSIVE_EXT;
322 
323    /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
324     * so just initialize all of them.
325     */
326    for (i = 0; i < MAX_VIEWPORTS; i++)
327       set_scissor_no_notify(ctx, i, 0, 0, 0, 0);
328 }
329