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
33static enum tnl_attr_format
34swtnl_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
61static 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
103static void
104swtnl_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
152static void
153swtnl_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
163static void
164swtnl_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
182static void
183swtnl_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
198static void
199swtnl_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
230static void
231swtnl_start(struct gl_context *ctx)
232{
233	swtnl_choose_attrs(ctx);
234}
235
236static void
237swtnl_finish(struct gl_context *ctx)
238{
239	swtnl_flush_vertices(ctx);
240	swtnl_unbind_vertices(ctx);
241}
242
243static void
244swtnl_primitive(struct gl_context *ctx, GLenum mode)
245{
246}
247
248static void
249swtnl_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
271static void
272swtnl_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
287static void
288swtnl_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
295static void
296swtnl_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
304static void
305swtnl_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. */
315void
316TAG(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
346void
347TAG(swtnl_destroy)(struct gl_context *ctx)
348{
349	nouveau_bo_ref(NULL, &to_render_state(ctx)->swtnl.vbo);
350}
351