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