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 /*
     28  * Vertex submission helper definitions shared among the software and
     29  * hardware TnL paths.
     30  */
     31 
     32 #include "nouveau_gldefs.h"
     33 
     34 #include "main/light.h"
     35 #include "vbo/vbo.h"
     36 #include "tnl/tnl.h"
     37 
     38 #define OUT_INDICES_L(r, i, d, n)		\
     39 	BATCH_OUT_L(i + d, n);			\
     40 	(void)r
     41 #define OUT_INDICES_I16(r, i, d, n)				\
     42 	BATCH_OUT_I16(r->ib.extract_u(&r->ib, 0, i) + d,	\
     43 		      r->ib.extract_u(&r->ib, 0, i + 1) + d)
     44 #define OUT_INDICES_I32(r, i, d, n)			\
     45 	BATCH_OUT_I32(r->ib.extract_u(&r->ib, 0, i) + d)
     46 
     47 /*
     48  * Emit <n> vertices using BATCH_OUT_<out>, MAX_OUT_<out> at a time,
     49  * grouping them in packets of length MAX_PACKET.
     50  *
     51  * out:   hardware index data type.
     52  * ctx:   GL context.
     53  * start: element within the index buffer to begin with.
     54  * delta: integer correction that will be added to each index found in
     55  *        the index buffer.
     56  */
     57 #define EMIT_VBO(out, ctx, start, delta, n) do {			\
     58 		struct nouveau_render_state *render = to_render_state(ctx); \
     59 		int _npush = n;						\
     60 									\
     61 		while (_npush) {						\
     62 			int _npack = MIN2(_npush, MAX_PACKET * MAX_OUT_##out); \
     63 			_npush -= _npack;					\
     64 									\
     65 			BATCH_PACKET_##out((_npack + MAX_OUT_##out - 1)	\
     66 					   / MAX_OUT_##out);		\
     67 			while (_npack) {				\
     68 				int _nout = MIN2(_npack, MAX_OUT_##out);\
     69 				_npack -= _nout;			\
     70 									\
     71 				OUT_INDICES_##out(render, start, delta, \
     72 						  _nout);		\
     73 				start += _nout;				\
     74 			}						\
     75 		}							\
     76 	} while (0)
     77 
     78 /*
     79  * Emit the <n>-th element of the array <a>, using IMM_OUT.
     80  */
     81 #define EMIT_IMM(ctx, a, n) do {					\
     82 		struct nouveau_attr_info *info =			\
     83 			&TAG(vertex_attrs)[(a)->attr];			\
     84 		int m;							\
     85 									\
     86 		if (!info->emit) {					\
     87 			IMM_PACKET(info->imm_method, info->imm_fields);	\
     88 									\
     89 			for (m = 0; m < (a)->fields; m++)		\
     90 				IMM_OUT((a)->extract_f(a, n, m));	\
     91 									\
     92 			for (m = (a)->fields; m < info->imm_fields; m++) \
     93 				IMM_OUT(((float []){0, 0, 0, 1})[m]);	\
     94 									\
     95 		} else {						\
     96 			info->emit(ctx, a, (a)->buf + n * (a)->stride);	\
     97 		}							\
     98 	} while (0)
     99 
    100 static void
    101 dispatch_l(struct gl_context *ctx, unsigned int start, int delta,
    102 	   unsigned int n)
    103 {
    104 	struct nouveau_pushbuf *push = context_push(ctx);
    105 	RENDER_LOCALS(ctx);
    106 
    107 	EMIT_VBO(L, ctx, start, delta, n);
    108 }
    109 
    110 static void
    111 dispatch_i32(struct gl_context *ctx, unsigned int start, int delta,
    112 	     unsigned int n)
    113 {
    114 	struct nouveau_pushbuf *push = context_push(ctx);
    115 	RENDER_LOCALS(ctx);
    116 
    117 	EMIT_VBO(I32, ctx, start, delta, n);
    118 }
    119 
    120 static void
    121 dispatch_i16(struct gl_context *ctx, unsigned int start, int delta,
    122 	     unsigned int n)
    123 {
    124 	struct nouveau_pushbuf *push = context_push(ctx);
    125 	RENDER_LOCALS(ctx);
    126 
    127 	EMIT_VBO(I32, ctx, start, delta, n & 1);
    128 	EMIT_VBO(I16, ctx, start, delta, n & ~1);
    129 }
    130 
    131 /*
    132  * Select an appropriate dispatch function for the given index buffer.
    133  */
    134 static dispatch_t
    135 get_array_dispatch(struct nouveau_array *a)
    136 {
    137 	if (!a->fields)
    138 		return dispatch_l;
    139 	else if (a->type == GL_UNSIGNED_INT)
    140 		return dispatch_i32;
    141 	else
    142 		return dispatch_i16;
    143 }
    144 
    145 /*
    146  * Returns how many vertices you can draw using <n> pushbuf dwords.
    147  */
    148 static inline unsigned
    149 get_max_vertices(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
    150 		 int n)
    151 {
    152 	struct nouveau_render_state *render = to_render_state(ctx);
    153 
    154 	if (render->mode == IMM) {
    155 		return MAX2(0, n - 4) / (render->vertex_size / 4 +
    156 					 render->attr_count);
    157 	} else {
    158 		unsigned max_out;
    159 
    160 		if (ib) {
    161 			switch (ib->index_size) {
    162 			case 4:
    163 				max_out = MAX_OUT_I32;
    164 				break;
    165 
    166 			case 2:
    167 				max_out = MAX_OUT_I16;
    168 				break;
    169 
    170 			case 1:
    171 				max_out = MAX_OUT_I16;
    172 				break;
    173 
    174 			default:
    175 				assert(0);
    176 				max_out = 0;
    177 				break;
    178 			}
    179 		} else {
    180 			max_out = MAX_OUT_L;
    181 		}
    182 
    183 		return MAX2(0, n - 7) * max_out * MAX_PACKET / (1 + MAX_PACKET);
    184 	}
    185 }
    186 
    187 static void
    188 TAG(emit_material)(struct gl_context *ctx, struct nouveau_array *a,
    189 		   const void *v)
    190 {
    191 	int attr = a->attr - VERT_ATTRIB_GENERIC0;
    192 	int state = ((int []) {
    193 			NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT,
    194 			NOUVEAU_STATE_MATERIAL_BACK_AMBIENT,
    195 			NOUVEAU_STATE_MATERIAL_FRONT_DIFFUSE,
    196 			NOUVEAU_STATE_MATERIAL_BACK_DIFFUSE,
    197 			NOUVEAU_STATE_MATERIAL_FRONT_SPECULAR,
    198 			NOUVEAU_STATE_MATERIAL_BACK_SPECULAR,
    199 			NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT,
    200 			NOUVEAU_STATE_MATERIAL_BACK_AMBIENT,
    201 			NOUVEAU_STATE_MATERIAL_FRONT_SHININESS,
    202 			NOUVEAU_STATE_MATERIAL_BACK_SHININESS
    203 		}) [attr];
    204 
    205 	COPY_4V(ctx->Light.Material.Attrib[attr], (float *)v);
    206 	_mesa_update_material(ctx, 1 << attr);
    207 
    208 	context_drv(ctx)->emit[state](ctx, state);
    209 }
    210