1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2009 VMware, Inc. 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 (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 /**
27 * \file condrender.c
28 * Conditional rendering functions
29 *
30 * \author Brian Paul
31 */
32
33 #include "glheader.h"
34 #include "condrender.h"
35 #include "enums.h"
36 #include "mtypes.h"
37 #include "queryobj.h"
38
39 #include "api_exec_decl.h"
40 #include "state_tracker/st_cb_bitmap.h"
41 #include "state_tracker/st_context.h"
42
43 static void
BeginConditionalRender(struct gl_context * ctx,struct gl_query_object * q,GLenum mode)44 BeginConditionalRender(struct gl_context *ctx, struct gl_query_object *q,
45 GLenum mode)
46 {
47 struct st_context *st = st_context(ctx);
48 uint m;
49 /* Don't invert the condition for rendering by default */
50 boolean inverted = FALSE;
51
52 st_flush_bitmap_cache(st);
53
54 switch (mode) {
55 case GL_QUERY_WAIT:
56 m = PIPE_RENDER_COND_WAIT;
57 break;
58 case GL_QUERY_NO_WAIT:
59 m = PIPE_RENDER_COND_NO_WAIT;
60 break;
61 case GL_QUERY_BY_REGION_WAIT:
62 m = PIPE_RENDER_COND_BY_REGION_WAIT;
63 break;
64 case GL_QUERY_BY_REGION_NO_WAIT:
65 m = PIPE_RENDER_COND_BY_REGION_NO_WAIT;
66 break;
67 case GL_QUERY_WAIT_INVERTED:
68 m = PIPE_RENDER_COND_WAIT;
69 inverted = TRUE;
70 break;
71 case GL_QUERY_NO_WAIT_INVERTED:
72 m = PIPE_RENDER_COND_NO_WAIT;
73 inverted = TRUE;
74 break;
75 case GL_QUERY_BY_REGION_WAIT_INVERTED:
76 m = PIPE_RENDER_COND_BY_REGION_WAIT;
77 inverted = TRUE;
78 break;
79 case GL_QUERY_BY_REGION_NO_WAIT_INVERTED:
80 m = PIPE_RENDER_COND_BY_REGION_NO_WAIT;
81 inverted = TRUE;
82 break;
83 default:
84 assert(0 && "bad mode in st_BeginConditionalRender");
85 m = PIPE_RENDER_COND_WAIT;
86 }
87
88 cso_set_render_condition(st->cso_context, q->pq, inverted, m);
89 }
90
91 static void
EndConditionalRender(struct gl_context * ctx,struct gl_query_object * q)92 EndConditionalRender(struct gl_context *ctx, struct gl_query_object *q)
93 {
94 struct st_context *st = st_context(ctx);
95 (void) q;
96
97 st_flush_bitmap_cache(st);
98
99 cso_set_render_condition(st->cso_context, NULL, FALSE, 0);
100 }
101
102 static ALWAYS_INLINE void
begin_conditional_render(struct gl_context * ctx,GLuint queryId,GLenum mode,bool no_error)103 begin_conditional_render(struct gl_context *ctx, GLuint queryId, GLenum mode,
104 bool no_error)
105 {
106 struct gl_query_object *q = NULL;
107
108 assert(ctx->Query.CondRenderMode == GL_NONE);
109
110 if (queryId != 0)
111 q = _mesa_lookup_query_object(ctx, queryId);
112
113 if (!no_error) {
114 /* Section 2.14 (Conditional Rendering) of the OpenGL 3.0 spec says:
115 *
116 * "The error INVALID_VALUE is generated if <id> is not the name of an
117 * existing query object query."
118 */
119 if (!q) {
120 _mesa_error(ctx, GL_INVALID_VALUE,
121 "glBeginConditionalRender(bad queryId=%u)", queryId);
122 return;
123 }
124 assert(q->Id == queryId);
125
126 switch (mode) {
127 case GL_QUERY_WAIT:
128 case GL_QUERY_NO_WAIT:
129 case GL_QUERY_BY_REGION_WAIT:
130 case GL_QUERY_BY_REGION_NO_WAIT:
131 break; /* OK */
132 case GL_QUERY_WAIT_INVERTED:
133 case GL_QUERY_NO_WAIT_INVERTED:
134 case GL_QUERY_BY_REGION_WAIT_INVERTED:
135 case GL_QUERY_BY_REGION_NO_WAIT_INVERTED:
136 if (ctx->Extensions.ARB_conditional_render_inverted)
137 break; /* OK */
138 FALLTHROUGH;
139 default:
140 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginConditionalRender(mode=%s)",
141 _mesa_enum_to_string(mode));
142 return;
143 }
144
145 /* Section 2.14 (Conditional Rendering) of the OpenGL 3.0 spec says:
146 *
147 * "The error INVALID_OPERATION is generated if <id> is the name of a
148 * query object with a target other than SAMPLES_PASSED, or <id> is
149 * the name of a query currently in progress."
150 */
151 if ((q->Target != GL_SAMPLES_PASSED &&
152 q->Target != GL_ANY_SAMPLES_PASSED &&
153 q->Target != GL_ANY_SAMPLES_PASSED_CONSERVATIVE &&
154 q->Target != GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB &&
155 q->Target != GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB) || q->Active) {
156 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginConditionalRender()");
157 return;
158 }
159 }
160
161 ctx->Query.CondRenderQuery = q;
162 ctx->Query.CondRenderMode = mode;
163
164 BeginConditionalRender(ctx, q, mode);
165 }
166
167
168 void GLAPIENTRY
_mesa_BeginConditionalRender_no_error(GLuint queryId,GLenum mode)169 _mesa_BeginConditionalRender_no_error(GLuint queryId, GLenum mode)
170 {
171 GET_CURRENT_CONTEXT(ctx);
172 begin_conditional_render(ctx, queryId, mode, true);
173 }
174
175
176 void GLAPIENTRY
_mesa_BeginConditionalRender(GLuint queryId,GLenum mode)177 _mesa_BeginConditionalRender(GLuint queryId, GLenum mode)
178 {
179 GET_CURRENT_CONTEXT(ctx);
180
181 /* Section 2.14 (Conditional Rendering) of the OpenGL 3.0 spec says:
182 *
183 * "If BeginConditionalRender is called while conditional rendering is
184 * in progress, or if EndConditionalRender is called while conditional
185 * rendering is not in progress, the error INVALID_OPERATION is
186 * generated."
187 */
188 if (!ctx->Extensions.NV_conditional_render || ctx->Query.CondRenderQuery) {
189 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginConditionalRender()");
190 return;
191 }
192
193 begin_conditional_render(ctx, queryId, mode, false);
194 }
195
196
197 static void
end_conditional_render(struct gl_context * ctx)198 end_conditional_render(struct gl_context *ctx)
199 {
200 FLUSH_VERTICES(ctx, 0, 0);
201
202 EndConditionalRender(ctx, ctx->Query.CondRenderQuery);
203
204 ctx->Query.CondRenderQuery = NULL;
205 ctx->Query.CondRenderMode = GL_NONE;
206 }
207
208
209 void APIENTRY
_mesa_EndConditionalRender_no_error(void)210 _mesa_EndConditionalRender_no_error(void)
211 {
212 GET_CURRENT_CONTEXT(ctx);
213 end_conditional_render(ctx);
214 }
215
216
217 void APIENTRY
_mesa_EndConditionalRender(void)218 _mesa_EndConditionalRender(void)
219 {
220 GET_CURRENT_CONTEXT(ctx);
221
222 if (!ctx->Extensions.NV_conditional_render || !ctx->Query.CondRenderQuery) {
223 _mesa_error(ctx, GL_INVALID_OPERATION, "glEndConditionalRender()");
224 return;
225 }
226
227 end_conditional_render(ctx);
228 }
229
230
231 /**
232 * This function is called by software rendering commands (all point,
233 * line triangle drawing, glClear, glDrawPixels, glCopyPixels, and
234 * glBitmap, glBlitFramebuffer) to determine if subsequent drawing
235 * commands should be
236 * executed or discarded depending on the current conditional
237 * rendering state. Ideally, this check would be implemented by the
238 * GPU when doing hardware rendering. XXX should this function be
239 * called via a new driver hook?
240 *
241 * \return GL_TRUE if we should render, GL_FALSE if we should discard
242 */
243 GLboolean
_mesa_check_conditional_render(struct gl_context * ctx)244 _mesa_check_conditional_render(struct gl_context *ctx)
245 {
246 struct gl_query_object *q = ctx->Query.CondRenderQuery;
247
248 if (!q) {
249 /* no query in progress - draw normally */
250 return GL_TRUE;
251 }
252
253 switch (ctx->Query.CondRenderMode) {
254 case GL_QUERY_BY_REGION_WAIT:
255 FALLTHROUGH;
256 case GL_QUERY_WAIT:
257 if (!q->Ready) {
258 _mesa_wait_query(ctx, q);
259 }
260 return q->Result > 0;
261 case GL_QUERY_BY_REGION_WAIT_INVERTED:
262 FALLTHROUGH;
263 case GL_QUERY_WAIT_INVERTED:
264 if (!q->Ready) {
265 _mesa_wait_query(ctx, q);
266 }
267 return q->Result == 0;
268 case GL_QUERY_BY_REGION_NO_WAIT:
269 FALLTHROUGH;
270 case GL_QUERY_NO_WAIT:
271 if (!q->Ready)
272 _mesa_check_query(ctx, q);
273 return q->Ready ? (q->Result > 0) : GL_TRUE;
274 case GL_QUERY_BY_REGION_NO_WAIT_INVERTED:
275 FALLTHROUGH;
276 case GL_QUERY_NO_WAIT_INVERTED:
277 if (!q->Ready)
278 _mesa_check_query(ctx, q);
279 return q->Ready ? (q->Result == 0) : GL_TRUE;
280 default:
281 _mesa_problem(ctx, "Bad cond render mode %s in "
282 " _mesa_check_conditional_render()",
283 _mesa_enum_to_string(ctx->Query.CondRenderMode));
284 return GL_TRUE;
285 }
286 }
287