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