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