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 #define SWTNL_VBO_SIZE 65536
32
33 static enum tnl_attr_format
swtnl_get_format(int type,int fields)34 swtnl_get_format(int type, int fields) {
35 switch (type) {
36 case GL_FLOAT:
37 switch (fields){
38 case 1:
39 return EMIT_1F;
40 case 2:
41 return EMIT_2F;
42 case 3:
43 return EMIT_3F;
44 case 4:
45 return EMIT_4F;
46 default:
47 assert(0);
48 }
49 case GL_UNSIGNED_BYTE:
50 switch (fields) {
51 case 4:
52 return EMIT_4UB_4F_RGBA;
53 default:
54 assert(0);
55 }
56 default:
57 assert(0);
58 }
59 }
60
61 static struct swtnl_attr_info {
62 int type;
63 int fields;
64 } swtnl_attrs[VERT_ATTRIB_MAX] = {
65 [VERT_ATTRIB_POS] = {
66 .type = GL_FLOAT,
67 .fields = 4,
68 },
69 [VERT_ATTRIB_NORMAL] = {
70 .type = GL_FLOAT,
71 .fields = -1,
72 },
73 [VERT_ATTRIB_COLOR0] = {
74 .type = GL_UNSIGNED_BYTE,
75 .fields = 4,
76 },
77 [VERT_ATTRIB_COLOR1] = {
78 .type = GL_UNSIGNED_BYTE,
79 .fields = 4,
80 },
81 [VERT_ATTRIB_FOG] = {
82 .type = GL_FLOAT,
83 .fields = 1,
84 },
85 [VERT_ATTRIB_TEX0] = {
86 .type = GL_FLOAT,
87 .fields = -1,
88 },
89 [VERT_ATTRIB_TEX1] = {
90 .type = GL_FLOAT,
91 .fields = -1,
92 },
93 [VERT_ATTRIB_TEX2] = {
94 .type = GL_FLOAT,
95 .fields = -1,
96 },
97 [VERT_ATTRIB_TEX3] = {
98 .type = GL_FLOAT,
99 .fields = -1,
100 },
101 };
102
103 static void
swtnl_choose_attrs(struct gl_context * ctx)104 swtnl_choose_attrs(struct gl_context *ctx)
105 {
106 struct nouveau_render_state *render = to_render_state(ctx);
107 TNLcontext *tnl = TNL_CONTEXT(ctx);
108 struct tnl_clipspace *vtx = &tnl->clipspace;
109 static struct tnl_attr_map map[NUM_VERTEX_ATTRS];
110 int fields, attr, i, n = 0;
111
112 render->mode = VBO;
113 render->attr_count = NUM_VERTEX_ATTRS;
114
115 /* We always want non Ndc coords format */
116 tnl->vb.AttribPtr[VERT_ATTRIB_POS] = tnl->vb.ClipPtr;
117
118 for (i = 0; i < VERT_ATTRIB_MAX; i++) {
119 struct nouveau_attr_info *ha = &TAG(vertex_attrs)[i];
120 struct swtnl_attr_info *sa = &swtnl_attrs[i];
121 struct nouveau_array *a = &render->attrs[i];
122
123 if (!sa->fields)
124 continue; /* Unsupported attribute. */
125
126 if (tnl->render_inputs_bitset & BITFIELD64_BIT(i)) {
127 if (sa->fields > 0)
128 fields = sa->fields;
129 else
130 fields = tnl->vb.AttribPtr[i]->size;
131
132 map[n++] = (struct tnl_attr_map) {
133 .attrib = i,
134 .format = swtnl_get_format(sa->type, fields),
135 };
136
137 render->map[ha->vbo_index] = i;
138 a->attr = i;
139 a->fields = fields;
140 a->type = sa->type;
141 }
142 }
143
144 _tnl_install_attrs(ctx, map, n, NULL, 0);
145
146 FOR_EACH_BOUND_ATTR(render, i, attr)
147 render->attrs[attr].stride = vtx->vertex_size;
148
149 TAG(render_set_format)(ctx);
150 }
151
152 static void
swtnl_alloc_vertices(struct gl_context * ctx)153 swtnl_alloc_vertices(struct gl_context *ctx)
154 {
155 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl;
156
157 nouveau_bo_ref(NULL, &swtnl->vbo);
158 swtnl->buf = nouveau_get_scratch(ctx, SWTNL_VBO_SIZE, &swtnl->vbo,
159 &swtnl->offset);
160 swtnl->vertex_count = 0;
161 }
162
163 static void
swtnl_bind_vertices(struct gl_context * ctx)164 swtnl_bind_vertices(struct gl_context *ctx)
165 {
166 struct nouveau_render_state *render = to_render_state(ctx);
167 struct nouveau_swtnl_state *swtnl = &render->swtnl;
168 struct tnl_clipspace *vtx = &TNL_CONTEXT(ctx)->clipspace;
169 int i;
170
171 for (i = 0; i < vtx->attr_count; i++) {
172 struct tnl_clipspace_attr *ta = &vtx->attr[i];
173 struct nouveau_array *a = &render->attrs[ta->attrib];
174
175 nouveau_bo_ref(swtnl->vbo, &a->bo);
176 a->offset = swtnl->offset + ta->vertoffset;
177 }
178
179 TAG(render_bind_vertices)(ctx);
180 }
181
182 static void
swtnl_unbind_vertices(struct gl_context * ctx)183 swtnl_unbind_vertices(struct gl_context *ctx)
184 {
185 struct nouveau_render_state *render = to_render_state(ctx);
186 int i, attr;
187
188 TAG(render_release_vertices)(ctx);
189
190 FOR_EACH_BOUND_ATTR(render, i, attr) {
191 nouveau_bo_ref(NULL, &render->attrs[attr].bo);
192 render->map[i] = -1;
193 }
194
195 render->attr_count = 0;
196 }
197
198 static void
swtnl_flush_vertices(struct gl_context * ctx)199 swtnl_flush_vertices(struct gl_context *ctx)
200 {
201 struct nouveau_pushbuf *push = context_push(ctx);
202 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl;
203 unsigned npush, start = 0, count = swtnl->vertex_count;
204 RENDER_LOCALS(ctx);
205
206 swtnl_bind_vertices(ctx);
207
208 while (count) {
209 npush = get_max_vertices(ctx, NULL, PUSH_AVAIL(push));
210 npush = MIN2(npush / 12 * 12, count);
211 count -= npush;
212
213 if (!npush) {
214 PUSH_KICK(push);
215 continue;
216 }
217
218 BATCH_BEGIN(nvgl_primitive(swtnl->primitive));
219 EMIT_VBO(L, ctx, start, 0, npush);
220 BATCH_END();
221
222 PUSH_KICK(push);
223 }
224
225 swtnl_alloc_vertices(ctx);
226 }
227
228 /* TnL renderer entry points */
229
230 static void
swtnl_start(struct gl_context * ctx)231 swtnl_start(struct gl_context *ctx)
232 {
233 swtnl_choose_attrs(ctx);
234 }
235
236 static void
swtnl_finish(struct gl_context * ctx)237 swtnl_finish(struct gl_context *ctx)
238 {
239 swtnl_flush_vertices(ctx);
240 swtnl_unbind_vertices(ctx);
241 }
242
243 static void
swtnl_primitive(struct gl_context * ctx,GLenum mode)244 swtnl_primitive(struct gl_context *ctx, GLenum mode)
245 {
246 }
247
248 static void
swtnl_reset_stipple(struct gl_context * ctx)249 swtnl_reset_stipple(struct gl_context *ctx)
250 {
251 }
252
253 /* Primitive rendering */
254
255 #define BEGIN_PRIMITIVE(p, n) \
256 struct nouveau_swtnl_state *swtnl = &to_render_state(ctx)->swtnl; \
257 int vertex_len = TNL_CONTEXT(ctx)->clipspace.vertex_size; \
258 \
259 if (swtnl->vertex_count + (n) > SWTNL_VBO_SIZE/vertex_len \
260 || (swtnl->vertex_count && swtnl->primitive != p)) \
261 swtnl_flush_vertices(ctx); \
262 \
263 swtnl->primitive = p;
264
265 #define OUT_VERTEX(i) do { \
266 memcpy(swtnl->buf + swtnl->vertex_count * vertex_len, \
267 _tnl_get_vertex(ctx, (i)), vertex_len); \
268 swtnl->vertex_count++; \
269 } while (0)
270
271 static void
swtnl_points(struct gl_context * ctx,GLuint first,GLuint last)272 swtnl_points(struct gl_context *ctx, GLuint first, GLuint last)
273 {
274 int i, count;
275
276 while (first < last) {
277 BEGIN_PRIMITIVE(GL_POINTS, last - first);
278
279 count = MIN2(SWTNL_VBO_SIZE / vertex_len, last - first);
280 for (i = 0; i < count; i++)
281 OUT_VERTEX(first + i);
282
283 first += count;
284 }
285 }
286
287 static void
swtnl_line(struct gl_context * ctx,GLuint v1,GLuint v2)288 swtnl_line(struct gl_context *ctx, GLuint v1, GLuint v2)
289 {
290 BEGIN_PRIMITIVE(GL_LINES, 2);
291 OUT_VERTEX(v1);
292 OUT_VERTEX(v2);
293 }
294
295 static void
swtnl_triangle(struct gl_context * ctx,GLuint v1,GLuint v2,GLuint v3)296 swtnl_triangle(struct gl_context *ctx, GLuint v1, GLuint v2, GLuint v3)
297 {
298 BEGIN_PRIMITIVE(GL_TRIANGLES, 3);
299 OUT_VERTEX(v1);
300 OUT_VERTEX(v2);
301 OUT_VERTEX(v3);
302 }
303
304 static void
swtnl_quad(struct gl_context * ctx,GLuint v1,GLuint v2,GLuint v3,GLuint v4)305 swtnl_quad(struct gl_context *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4)
306 {
307 BEGIN_PRIMITIVE(GL_QUADS, 4);
308 OUT_VERTEX(v1);
309 OUT_VERTEX(v2);
310 OUT_VERTEX(v3);
311 OUT_VERTEX(v4);
312 }
313
314 /* TnL initialization. */
315 void
TAG(swtnl_init)316 TAG(swtnl_init)(struct gl_context *ctx)
317 {
318 TNLcontext *tnl = TNL_CONTEXT(ctx);
319
320 tnl->Driver.RunPipeline = _tnl_run_pipeline;
321 tnl->Driver.Render.Interp = _tnl_interp;
322 tnl->Driver.Render.CopyPV = _tnl_copy_pv;
323 tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon;
324 tnl->Driver.Render.ClippedLine = _tnl_RenderClippedLine;
325 tnl->Driver.Render.BuildVertices = _tnl_build_vertices;
326
327 tnl->Driver.Render.Start = swtnl_start;
328 tnl->Driver.Render.Finish = swtnl_finish;
329 tnl->Driver.Render.PrimitiveNotify = swtnl_primitive;
330 tnl->Driver.Render.ResetLineStipple = swtnl_reset_stipple;
331
332 tnl->Driver.Render.Points = swtnl_points;
333 tnl->Driver.Render.Line = swtnl_line;
334 tnl->Driver.Render.Triangle = swtnl_triangle;
335 tnl->Driver.Render.Quad = swtnl_quad;
336
337 _tnl_init_vertices(ctx, tnl->vb.Size,
338 NUM_VERTEX_ATTRS * 4 * sizeof(GLfloat));
339 _tnl_need_projected_coords(ctx, GL_FALSE);
340 _tnl_allow_vertex_fog(ctx, GL_FALSE);
341 _tnl_wakeup(ctx);
342
343 swtnl_alloc_vertices(ctx);
344 }
345
346 void
TAG(swtnl_destroy)347 TAG(swtnl_destroy)(struct gl_context *ctx)
348 {
349 nouveau_bo_ref(NULL, &to_render_state(ctx)->swtnl.vbo);
350 }
351