Merge remote-tracking branch 'mesa-public/master' into vulkan
[mesa.git] / src / mesa / main / scissor.c
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/mtypes.h"
29 #include "main/scissor.h"
30
31
32 /**
33 * Set scissor rectangle data directly in ScissorArray
34 *
35 * This is an internal function that performs no error checking on the
36 * supplied data. It also does \b not call \c dd_function_table::Scissor.
37 *
38 * \sa _mesa_set_scissor
39 */
40 static void
41 set_scissor_no_notify(struct gl_context *ctx, unsigned idx,
42 GLint x, GLint y, GLsizei width, GLsizei height)
43 {
44 if (x == ctx->Scissor.ScissorArray[idx].X &&
45 y == ctx->Scissor.ScissorArray[idx].Y &&
46 width == ctx->Scissor.ScissorArray[idx].Width &&
47 height == ctx->Scissor.ScissorArray[idx].Height)
48 return;
49
50 FLUSH_VERTICES(ctx, _NEW_SCISSOR);
51 ctx->Scissor.ScissorArray[idx].X = x;
52 ctx->Scissor.ScissorArray[idx].Y = y;
53 ctx->Scissor.ScissorArray[idx].Width = width;
54 ctx->Scissor.ScissorArray[idx].Height = height;
55 }
56
57 /**
58 * Called via glScissor
59 */
60 void GLAPIENTRY
61 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
62 {
63 unsigned i;
64 GET_CURRENT_CONTEXT(ctx);
65
66 if (MESA_VERBOSE & VERBOSE_API)
67 _mesa_debug(ctx, "glScissor %d %d %d %d\n", x, y, width, height);
68
69 if (width < 0 || height < 0) {
70 _mesa_error( ctx, GL_INVALID_VALUE, "glScissor" );
71 return;
72 }
73
74 /* The GL_ARB_viewport_array spec says:
75 *
76 * "Scissor sets the scissor rectangle for all viewports to the same
77 * values and is equivalent (assuming no errors are generated) to:
78 *
79 * for (uint i = 0; i < MAX_VIEWPORTS; i++) {
80 * ScissorIndexed(i, left, bottom, width, height);
81 * }"
82 *
83 * Set the scissor rectangle for all of the viewports supported by the
84 * implementation, but only signal the driver once at the end.
85 */
86 for (i = 0; i < ctx->Const.MaxViewports; i++)
87 set_scissor_no_notify(ctx, i, x, y, width, height);
88
89 if (ctx->Driver.Scissor)
90 ctx->Driver.Scissor(ctx);
91 }
92
93
94 /**
95 * Define the scissor box.
96 *
97 * \param x, y coordinates of the scissor box lower-left corner.
98 * \param width width of the scissor box.
99 * \param height height of the scissor box.
100 *
101 * \sa glScissor().
102 *
103 * Verifies the parameters and updates __struct gl_contextRec::Scissor. On a
104 * change flushes the vertices and notifies the driver via
105 * the dd_function_table::Scissor callback.
106 */
107 void
108 _mesa_set_scissor(struct gl_context *ctx, unsigned idx,
109 GLint x, GLint y, GLsizei width, GLsizei height)
110 {
111 set_scissor_no_notify(ctx, idx, x, y, width, height);
112
113 if (ctx->Driver.Scissor)
114 ctx->Driver.Scissor(ctx);
115 }
116
117 /**
118 * Define count scissor boxes starting at index.
119 *
120 * \param index index of first scissor records to set
121 * \param count number of scissor records to set
122 * \param x, y pointer to array of struct gl_scissor_rects
123 *
124 * \sa glScissorArrayv().
125 *
126 * Verifies the parameters and call set_scissor_no_notify to do the work.
127 */
128 void GLAPIENTRY
129 _mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v)
130 {
131 int i;
132 struct gl_scissor_rect *p = (struct gl_scissor_rect *) v;
133 GET_CURRENT_CONTEXT(ctx);
134
135 if ((first + count) > ctx->Const.MaxViewports) {
136 _mesa_error(ctx, GL_INVALID_VALUE,
137 "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)",
138 first, count, ctx->Const.MaxViewports);
139 return;
140 }
141
142 /* Verify width & height */
143 for (i = 0; i < count; i++) {
144 if (p[i].Width < 0 || p[i].Height < 0) {
145 _mesa_error(ctx, GL_INVALID_VALUE,
146 "glScissorArrayv: index (%d) width or height < 0 (%d, %d)",
147 i, p[i].Width, p[i].Height);
148 return;
149 }
150 }
151
152 for (i = 0; i < count; i++)
153 set_scissor_no_notify(ctx, i + first,
154 p[i].X, p[i].Y, p[i].Width, p[i].Height);
155
156 if (ctx->Driver.Scissor)
157 ctx->Driver.Scissor(ctx);
158 }
159
160 /**
161 * Define the scissor box.
162 *
163 * \param index index of scissor records to set
164 * \param x, y coordinates of the scissor box lower-left corner.
165 * \param width width of the scissor box.
166 * \param height height of the scissor box.
167 *
168 * Verifies the parameters call set_scissor_no_notify to do the work.
169 */
170 static void
171 ScissorIndexed(GLuint index, GLint left, GLint bottom,
172 GLsizei width, GLsizei height, const char *function)
173 {
174 GET_CURRENT_CONTEXT(ctx);
175
176 if (MESA_VERBOSE & VERBOSE_API)
177 _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n",
178 function, index, left, bottom, width, height);
179
180 if (index >= ctx->Const.MaxViewports) {
181 _mesa_error(ctx, GL_INVALID_VALUE,
182 "%s: index (%d) >= MaxViewports (%d)",
183 function, index, ctx->Const.MaxViewports);
184 return;
185 }
186
187 if (width < 0 || height < 0) {
188 _mesa_error(ctx, GL_INVALID_VALUE,
189 "%s: index (%d) width or height < 0 (%d, %d)",
190 function, index, width, height);
191 return;
192 }
193
194 set_scissor_no_notify(ctx, index, left, bottom, width, height);
195
196 if (ctx->Driver.Scissor)
197 ctx->Driver.Scissor(ctx);
198 }
199
200 void GLAPIENTRY
201 _mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom,
202 GLsizei width, GLsizei height)
203 {
204 ScissorIndexed(index, left, bottom, width, height, "glScissorIndexed");
205 }
206
207 void GLAPIENTRY
208 _mesa_ScissorIndexedv(GLuint index, const GLint *v)
209 {
210 ScissorIndexed(index, v[0], v[1], v[2], v[3], "glScissorIndexedv");
211 }
212
213 /**
214 * Initialize the context's scissor state.
215 * \param ctx the GL context.
216 */
217 void
218 _mesa_init_scissor(struct gl_context *ctx)
219 {
220 unsigned i;
221
222 /* Scissor group */
223 ctx->Scissor.EnableFlags = 0;
224
225 /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
226 * so just initialize all of them.
227 */
228 for (i = 0; i < MAX_VIEWPORTS; i++)
229 set_scissor_no_notify(ctx, i, 0, 0, 0, 0);
230 }