dri/nouveau: Try to keep client buffers smaller than the scratch VBO length.
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_swtnl_t.c
1 /*
2 * Copyright (C) 2009-2010 Francisco Jerez.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27 #include "tnl/t_context.h"
28 #include "tnl/t_pipeline.h"
29 #include "tnl/t_vertex.h"
30
31 static enum tnl_attr_format
32 swtnl_get_format(int type, int fields) {
33 switch (type) {
34 case GL_FLOAT:
35 switch (fields){
36 case 1:
37 return EMIT_1F;
38 case 2:
39 return EMIT_2F;
40 case 3:
41 return EMIT_3F;
42 case 4:
43 return EMIT_4F;
44 default:
45 assert(0);
46 }
47 case GL_UNSIGNED_BYTE:
48 switch (fields) {
49 case 4:
50 return EMIT_4UB_4F_RGBA;
51 default:
52 assert(0);
53 }
54 default:
55 assert(0);
56 }
57 }
58
59 static struct swtnl_attr_info {
60 int type;
61 int fields;
62 } swtnl_attrs[VERT_ATTRIB_MAX] = {
63 [VERT_ATTRIB_POS] = {
64 .type = GL_FLOAT,
65 .fields = 4,
66 },
67 [VERT_ATTRIB_NORMAL] = {
68 .type = GL_FLOAT,
69 .fields = -1,
70 },
71 [VERT_ATTRIB_COLOR0] = {
72 .type = GL_UNSIGNED_BYTE,
73 .fields = 4,
74 },
75 [VERT_ATTRIB_COLOR1] = {
76 .type = GL_UNSIGNED_BYTE,
77 .fields = 4,
78 },
79 [VERT_ATTRIB_FOG] = {
80 .type = GL_FLOAT,
81 .fields = 1,
82 },
83 [VERT_ATTRIB_TEX0] = {
84 .type = GL_FLOAT,
85 .fields = -1,
86 },
87 [VERT_ATTRIB_TEX1] = {
88 .type = GL_FLOAT,
89 .fields = -1,
90 },
91 [VERT_ATTRIB_TEX2] = {
92 .type = GL_FLOAT,
93 .fields = -1,
94 },
95 [VERT_ATTRIB_TEX3] = {
96 .type = GL_FLOAT,
97 .fields = -1,
98 },
99 };
100
101 static void
102 swtnl_choose_attrs(GLcontext *ctx)
103 {
104 struct nouveau_render_state *render = to_render_state(ctx);
105 TNLcontext *tnl = TNL_CONTEXT(ctx);
106 struct tnl_clipspace *vtx = &tnl->clipspace;
107 static struct tnl_attr_map map[NUM_VERTEX_ATTRS];
108 int fields, i, n = 0;
109
110 render->mode = VBO;
111 render->attr_count = NUM_VERTEX_ATTRS;
112
113 /* We always want non Ndc coords format */
114 tnl->vb.AttribPtr[VERT_ATTRIB_POS] = tnl->vb.ClipPtr;
115
116 for (i = 0; i < VERT_ATTRIB_MAX; i++) {
117 struct nouveau_attr_info *ha = &TAG(vertex_attrs)[i];
118 struct swtnl_attr_info *sa = &swtnl_attrs[i];
119 struct nouveau_array_state *a = &render->attrs[i];
120
121 if (!sa->fields)
122 continue; /* Unsupported attribute. */
123
124 if (RENDERINPUTS_TEST(tnl->render_inputs_bitset, i)) {
125 if (sa->fields > 0)
126 fields = sa->fields;
127 else
128 fields = tnl->vb.AttribPtr[i]->size;
129
130 map[n++] = (struct tnl_attr_map) {
131 .attrib = i,
132 .format = swtnl_get_format(sa->type, fields),
133 };
134
135 render->map[ha->vbo_index] = i;
136 a->attr = i;
137 a->fields = fields;
138 a->type = sa->type;
139 }
140 }
141
142 _tnl_install_attrs(ctx, map, n, NULL, 0);
143
144 for (i = 0; i < vtx->attr_count; i++) {
145 struct tnl_clipspace_attr *ta = &vtx->attr[i];
146 struct nouveau_array_state *a = &render->attrs[ta->attrib];
147
148 a->stride = vtx->vertex_size;
149 a->offset = ta->vertoffset;
150 }
151
152 TAG(render_set_format)(ctx);
153 }
154
155 static void
156 swtnl_alloc_vertices(GLcontext *ctx)
157 {
158 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl;
159
160 nouveau_bo_ref(NULL, &swtnl->vbo);
161 swtnl->buf = get_scratch_vbo(ctx, RENDER_SCRATCH_SIZE,
162 &swtnl->vbo, NULL);
163 swtnl->vertex_count = 0;
164 }
165
166 static void
167 swtnl_bind_vertices(GLcontext *ctx)
168 {
169 struct nouveau_render_state *render = to_render_state(ctx);
170 struct nouveau_swtnl_state *swtnl = &render->swtnl;
171 int i;
172
173 for (i = 0; i < render->attr_count; i++) {
174 int attr = render->map[i];
175
176 if (attr >= 0)
177 nouveau_bo_ref(swtnl->vbo,
178 &render->attrs[attr].bo);
179 }
180
181 TAG(render_bind_vertices)(ctx);
182 }
183
184 static void
185 swtnl_unbind_vertices(GLcontext *ctx)
186 {
187 struct nouveau_render_state *render = to_render_state(ctx);
188 int i;
189
190 for (i = 0; i < render->attr_count; i++) {
191 int *attr = &render->map[i];
192
193 if (*attr >= 0) {
194 nouveau_bo_ref(NULL, &render->attrs[*attr].bo);
195 *attr = -1;
196 }
197 }
198
199 render->attr_count = 0;
200 }
201
202 static void
203 swtnl_flush_vertices(GLcontext *ctx)
204 {
205 struct nouveau_channel *chan = context_chan(ctx);
206 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl;
207 unsigned push, start = 0, count = swtnl->vertex_count;
208 RENDER_LOCALS(ctx);
209
210 swtnl_bind_vertices(ctx);
211
212 while (count) {
213 push = get_max_vertices(ctx, NULL, AVAIL_RING(chan));
214 push = MIN2(push / 12 * 12, count);
215 count -= push;
216
217 if (!push) {
218 FIRE_RING(chan);
219 continue;
220 }
221
222 BATCH_BEGIN(nvgl_primitive(swtnl->primitive));
223 EMIT_VBO(L, ctx, start, 0, push);
224 BATCH_END();
225
226 FIRE_RING(chan);
227 }
228
229 swtnl_alloc_vertices(ctx);
230 }
231
232 /* TnL renderer entry points */
233
234 static void
235 swtnl_start(GLcontext *ctx)
236 {
237 swtnl_choose_attrs(ctx);
238 }
239
240 static void
241 swtnl_finish(GLcontext *ctx)
242 {
243 swtnl_flush_vertices(ctx);
244 swtnl_unbind_vertices(ctx);
245 }
246
247 static void
248 swtnl_primitive(GLcontext *ctx, GLenum mode)
249 {
250 }
251
252 static void
253 swtnl_reset_stipple(GLcontext *ctx)
254 {
255 }
256
257 /* Primitive rendering */
258
259 #define BEGIN_PRIMITIVE(p, n) \
260 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl; \
261 int vertex_len = TNL_CONTEXT(ctx)->clipspace.vertex_size; \
262 \
263 if (swtnl->vertex_count + (n) > swtnl->vbo->size/vertex_len \
264 || (swtnl->vertex_count && swtnl->primitive != p)) \
265 swtnl_flush_vertices(ctx); \
266 \
267 swtnl->primitive = p;
268
269 #define OUT_VERTEX(i) do { \
270 memcpy(swtnl->buf + swtnl->vertex_count * vertex_len, \
271 _tnl_get_vertex(ctx, (i)), vertex_len); \
272 swtnl->vertex_count++; \
273 } while (0)
274
275 static void
276 swtnl_points(GLcontext *ctx, GLuint first, GLuint last)
277 {
278 int i, count;
279
280 while (first < last) {
281 BEGIN_PRIMITIVE(GL_POINTS, last - first);
282
283 count = MIN2(swtnl->vbo->size / vertex_len, last - first);
284 for (i = 0; i < count; i++)
285 OUT_VERTEX(first + i);
286
287 first += count;
288 }
289 }
290
291 static void
292 swtnl_line(GLcontext *ctx, GLuint v1, GLuint v2)
293 {
294 BEGIN_PRIMITIVE(GL_LINES, 2);
295 OUT_VERTEX(v1);
296 OUT_VERTEX(v2);
297 }
298
299 static void
300 swtnl_triangle(GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3)
301 {
302 BEGIN_PRIMITIVE(GL_TRIANGLES, 3);
303 OUT_VERTEX(v1);
304 OUT_VERTEX(v2);
305 OUT_VERTEX(v3);
306 }
307
308 static void
309 swtnl_quad(GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4)
310 {
311 BEGIN_PRIMITIVE(GL_QUADS, 4);
312 OUT_VERTEX(v1);
313 OUT_VERTEX(v2);
314 OUT_VERTEX(v3);
315 OUT_VERTEX(v4);
316 }
317
318 /* TnL initialization. */
319 static void
320 TAG(swtnl_init)(GLcontext *ctx)
321 {
322 TNLcontext *tnl = TNL_CONTEXT(ctx);
323
324 tnl->Driver.RunPipeline = _tnl_run_pipeline;
325 tnl->Driver.Render.Interp = _tnl_interp;
326 tnl->Driver.Render.CopyPV = _tnl_copy_pv;
327 tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon;
328 tnl->Driver.Render.ClippedLine = _tnl_RenderClippedLine;
329 tnl->Driver.Render.BuildVertices = _tnl_build_vertices;
330
331 tnl->Driver.Render.Start = swtnl_start;
332 tnl->Driver.Render.Finish = swtnl_finish;
333 tnl->Driver.Render.PrimitiveNotify = swtnl_primitive;
334 tnl->Driver.Render.ResetLineStipple = swtnl_reset_stipple;
335
336 tnl->Driver.Render.Points = swtnl_points;
337 tnl->Driver.Render.Line = swtnl_line;
338 tnl->Driver.Render.Triangle = swtnl_triangle;
339 tnl->Driver.Render.Quad = swtnl_quad;
340
341 _tnl_init_vertices(ctx, tnl->vb.Size,
342 NUM_VERTEX_ATTRS * 4 * sizeof(GLfloat));
343 _tnl_need_projected_coords(ctx, GL_FALSE);
344 _tnl_allow_vertex_fog(ctx, GL_FALSE);
345 _tnl_wakeup(ctx);
346
347 swtnl_alloc_vertices(ctx);
348 }
349
350 static void
351 TAG(swtnl_destroy)(GLcontext *ctx)
352 {
353 nouveau_bo_ref(NULL, &to_render_state(ctx)->swtnl.vbo);
354 }