xref: /third_party/mesa3d/src/mesa/main/condrender.c (revision bf215546)
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
43static void
44BeginConditionalRender(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
91static void
92EndConditionalRender(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
102static ALWAYS_INLINE void
103begin_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
168void GLAPIENTRY
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
176void GLAPIENTRY
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
197static void
198end_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
209void APIENTRY
210_mesa_EndConditionalRender_no_error(void)
211{
212   GET_CURRENT_CONTEXT(ctx);
213   end_conditional_render(ctx);
214}
215
216
217void APIENTRY
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 */
243GLboolean
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