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