vbo_exec.c revision 848b8605
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2005 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 * Authors: 25 * Keith Whitwell <keithw@vmware.com> 26 */ 27 28 29#include "main/api_arrayelt.h" 30#include "main/glheader.h" 31#include "main/mtypes.h" 32#include "main/vtxfmt.h" 33#include "vbo_context.h" 34 35 36 37void vbo_exec_init( struct gl_context *ctx ) 38{ 39 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 40 41 exec->ctx = ctx; 42 43 /* Initialize the arrayelt helper 44 */ 45 if (!ctx->aelt_context && 46 !_ae_create_context( ctx )) 47 return; 48 49 vbo_exec_vtx_init( exec ); 50 51 ctx->Driver.NeedFlush = 0; 52 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 53 ctx->Driver.BeginVertices = vbo_exec_BeginVertices; 54 ctx->Driver.FlushVertices = vbo_exec_FlushVertices; 55 56 vbo_exec_invalidate_state( ctx, ~0 ); 57} 58 59 60void vbo_exec_destroy( struct gl_context *ctx ) 61{ 62 struct vbo_exec_context *exec = &vbo_context(ctx)->exec; 63 64 if (ctx->aelt_context) { 65 _ae_destroy_context( ctx ); 66 ctx->aelt_context = NULL; 67 } 68 69 vbo_exec_vtx_destroy( exec ); 70} 71 72 73/** 74 * Really want to install these callbacks to a central facility to be 75 * invoked according to the state flags. That will have to wait for a 76 * mesa rework: 77 */ 78void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state ) 79{ 80 struct vbo_context *vbo = vbo_context(ctx); 81 struct vbo_exec_context *exec = &vbo->exec; 82 83 if (!exec->validating && new_state & (_NEW_PROGRAM|_NEW_ARRAY)) { 84 exec->array.recalculate_inputs = GL_TRUE; 85 } 86 87 if (new_state & _NEW_EVAL) 88 exec->eval.recalculate_maps = GL_TRUE; 89 90 _ae_invalidate_state(ctx, new_state); 91} 92 93 94/** 95 * Figure out the number of transform feedback primitives that will be output 96 * considering the drawing mode, number of vertices, and instance count, 97 * assuming that no geometry shading is done and primitive restart is not 98 * used. 99 * 100 * This is used by driver back-ends in implementing the PRIMITIVES_GENERATED 101 * and TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN queries. It is also used to 102 * pre-validate draw calls in GLES3 (where draw calls only succeed if there is 103 * enough room in the transform feedback buffer for the result). 104 */ 105size_t 106vbo_count_tessellated_primitives(GLenum mode, GLuint count, 107 GLuint num_instances) 108{ 109 size_t num_primitives; 110 switch (mode) { 111 case GL_POINTS: 112 num_primitives = count; 113 break; 114 case GL_LINE_STRIP: 115 num_primitives = count >= 2 ? count - 1 : 0; 116 break; 117 case GL_LINE_LOOP: 118 num_primitives = count >= 2 ? count : 0; 119 break; 120 case GL_LINES: 121 num_primitives = count / 2; 122 break; 123 case GL_TRIANGLE_STRIP: 124 case GL_TRIANGLE_FAN: 125 case GL_POLYGON: 126 num_primitives = count >= 3 ? count - 2 : 0; 127 break; 128 case GL_TRIANGLES: 129 num_primitives = count / 3; 130 break; 131 case GL_QUAD_STRIP: 132 num_primitives = count >= 4 ? ((count / 2) - 1) * 2 : 0; 133 break; 134 case GL_QUADS: 135 num_primitives = (count / 4) * 2; 136 break; 137 case GL_LINES_ADJACENCY: 138 num_primitives = count / 4; 139 break; 140 case GL_LINE_STRIP_ADJACENCY: 141 num_primitives = count >= 4 ? count - 3 : 0; 142 break; 143 case GL_TRIANGLES_ADJACENCY: 144 num_primitives = count / 6; 145 break; 146 case GL_TRIANGLE_STRIP_ADJACENCY: 147 num_primitives = count >= 6 ? (count - 4) / 2 : 0; 148 break; 149 default: 150 assert(!"Unexpected primitive type in count_tessellated_primitives"); 151 num_primitives = 0; 152 break; 153 } 154 return num_primitives * num_instances; 155} 156 157 158 159/** 160 * In some degenarate cases we can improve our ability to merge 161 * consecutive primitives. For example: 162 * glBegin(GL_LINE_STRIP); 163 * glVertex(1); 164 * glVertex(1); 165 * glEnd(); 166 * glBegin(GL_LINE_STRIP); 167 * glVertex(1); 168 * glVertex(1); 169 * glEnd(); 170 * Can be merged as a GL_LINES prim with four vertices. 171 * 172 * This function converts 2-vertex line strips/loops into GL_LINES, etc. 173 */ 174void 175vbo_try_prim_conversion(struct _mesa_prim *p) 176{ 177 if (p->mode == GL_LINE_STRIP && p->count == 2) { 178 /* convert 2-vertex line strip to a separate line */ 179 p->mode = GL_LINES; 180 } 181 else if ((p->mode == GL_TRIANGLE_STRIP || p->mode == GL_TRIANGLE_FAN) 182 && p->count == 3) { 183 /* convert 3-vertex tri strip or fan to a separate triangle */ 184 p->mode = GL_TRIANGLES; 185 } 186 187 /* Note: we can't convert a 4-vertex quad strip to a separate quad 188 * because the vertex ordering is different. We'd have to muck 189 * around in the vertex data to make it work. 190 */ 191} 192 193 194/** 195 * Helper function for determining if two subsequent glBegin/glEnd 196 * primitives can be combined. This is only possible for GL_POINTS, 197 * GL_LINES, GL_TRIANGLES and GL_QUADS. 198 * If we return true, it means that we can concatenate p1 onto p0 (and 199 * discard p1). 200 */ 201bool 202vbo_can_merge_prims(const struct _mesa_prim *p0, const struct _mesa_prim *p1) 203{ 204 if (!p0->begin || 205 !p1->begin || 206 !p0->end || 207 !p1->end) 208 return false; 209 210 /* The prim mode must match (ex: both GL_TRIANGLES) */ 211 if (p0->mode != p1->mode) 212 return false; 213 214 /* p1's vertices must come right after p0 */ 215 if (p0->start + p0->count != p1->start) 216 return false; 217 218 if (p0->basevertex != p1->basevertex || 219 p0->num_instances != p1->num_instances || 220 p0->base_instance != p1->base_instance) 221 return false; 222 223 /* can always merge subsequent GL_POINTS primitives */ 224 if (p0->mode == GL_POINTS) 225 return true; 226 227 /* independent lines with no extra vertices */ 228 if (p0->mode == GL_LINES && p0->count % 2 == 0 && p1->count % 2 == 0) 229 return true; 230 231 /* independent tris */ 232 if (p0->mode == GL_TRIANGLES && p0->count % 3 == 0 && p1->count % 3 == 0) 233 return true; 234 235 /* independent quads */ 236 if (p0->mode == GL_QUADS && p0->count % 4 == 0 && p1->count % 4 == 0) 237 return true; 238 239 return false; 240} 241 242 243/** 244 * If we've determined that p0 and p1 can be merged, this function 245 * concatenates p1 onto p0. 246 */ 247void 248vbo_merge_prims(struct _mesa_prim *p0, const struct _mesa_prim *p1) 249{ 250 assert(vbo_can_merge_prims(p0, p1)); 251 252 p0->count += p1->count; 253 p0->end = p1->end; 254} 255