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