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