Home | History | Annotate | Download | only in nouveau
      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
     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
    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
    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
    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
    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
    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
    231 swtnl_start(struct gl_context *ctx)
    232 {
    233 	swtnl_choose_attrs(ctx);
    234 }
    235 
    236 static void
    237 swtnl_finish(struct gl_context *ctx)
    238 {
    239 	swtnl_flush_vertices(ctx);
    240 	swtnl_unbind_vertices(ctx);
    241 }
    242 
    243 static void
    244 swtnl_primitive(struct gl_context *ctx, GLenum mode)
    245 {
    246 }
    247 
    248 static void
    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
    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
    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
    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
    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
    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
    347 TAG(swtnl_destroy)(struct gl_context *ctx)
    348 {
    349 	nouveau_bo_ref(NULL, &to_render_state(ctx)->swtnl.vbo);
    350 }
    351