• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
dispatch_l(struct gl_context * ctx,unsigned int start,int delta,unsigned int n)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
dispatch_i32(struct gl_context * ctx,unsigned int start,int delta,unsigned int n)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
dispatch_i16(struct gl_context * ctx,unsigned int start,int delta,unsigned int n)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
get_array_dispatch(struct nouveau_array * a)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
get_max_vertices(struct gl_context * ctx,const struct _mesa_index_buffer * ib,int n)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
TAG(emit_material)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