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 
vbo_exec_init(struct gl_context * ctx)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 
vbo_exec_destroy(struct gl_context * ctx)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  */
vbo_exec_invalidate_state(struct gl_context * ctx,GLbitfield new_state)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
vbo_count_tessellated_primitives(GLenum mode,GLuint count,GLuint num_instances)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
vbo_try_prim_conversion(struct _mesa_prim * p)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
vbo_can_merge_prims(const struct _mesa_prim * p0,const struct _mesa_prim * p1)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
vbo_merge_prims(struct _mesa_prim * p0,const struct _mesa_prim * p1)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