draw: corrections to allow for different cliptest cases
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_render_t.c
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 /*
101 * Select an appropriate dispatch function for the given index buffer.
102 */
103 static void
104 get_array_dispatch(struct nouveau_array_state *a, dispatch_t *dispatch)
105 {
106 if (!a->fields) {
107 auto void f(GLcontext *, unsigned int, int, unsigned int);
108
109 void f(GLcontext *ctx, unsigned int start, int delta,
110 unsigned int n) {
111 struct nouveau_channel *chan = context_chan(ctx);
112 RENDER_LOCALS(ctx);
113
114 EMIT_VBO(L, ctx, start, delta, n);
115 };
116
117 *dispatch = f;
118
119 } else if (a->type == GL_UNSIGNED_INT) {
120 auto void f(GLcontext *, unsigned int, int, unsigned int);
121
122 void f(GLcontext *ctx, unsigned int start, int delta,
123 unsigned int n) {
124 struct nouveau_channel *chan = context_chan(ctx);
125 RENDER_LOCALS(ctx);
126
127 EMIT_VBO(I32, ctx, start, delta, n);
128 };
129
130 *dispatch = f;
131
132 } else {
133 auto void f(GLcontext *, unsigned int, int, unsigned int);
134
135 void f(GLcontext *ctx, unsigned int start, int delta,
136 unsigned int n) {
137 struct nouveau_channel *chan = context_chan(ctx);
138 RENDER_LOCALS(ctx);
139
140 EMIT_VBO(I32, ctx, start, delta, n & 1);
141 EMIT_VBO(I16, ctx, start, delta, n & ~1);
142 };
143
144 *dispatch = f;
145 }
146 }
147
148 /*
149 * Select appropriate element extraction functions for the given
150 * array.
151 */
152 static void
153 get_array_extract(struct nouveau_array_state *a,
154 extract_u_t *extract_u, extract_f_t *extract_f)
155 {
156 #define EXTRACT(in_t, out_t, k) \
157 ({ \
158 auto out_t f(struct nouveau_array_state *, int, int); \
159 out_t f(struct nouveau_array_state *a, int i, int j) { \
160 in_t x = ((in_t *)(a->buf + i * a->stride))[j]; \
161 \
162 return (out_t)x / (k); \
163 }; \
164 f; \
165 });
166
167 switch (a->type) {
168 case GL_BYTE:
169 *extract_u = EXTRACT(char, unsigned, 1);
170 *extract_f = EXTRACT(char, float, SCHAR_MAX);
171 break;
172 case GL_UNSIGNED_BYTE:
173 *extract_u = EXTRACT(unsigned char, unsigned, 1);
174 *extract_f = EXTRACT(unsigned char, float, UCHAR_MAX);
175 break;
176 case GL_SHORT:
177 *extract_u = EXTRACT(short, unsigned, 1);
178 *extract_f = EXTRACT(short, float, SHRT_MAX);
179 break;
180 case GL_UNSIGNED_SHORT:
181 *extract_u = EXTRACT(unsigned short, unsigned, 1);
182 *extract_f = EXTRACT(unsigned short, float, USHRT_MAX);
183 break;
184 case GL_INT:
185 *extract_u = EXTRACT(int, unsigned, 1);
186 *extract_f = EXTRACT(int, float, INT_MAX);
187 break;
188 case GL_UNSIGNED_INT:
189 *extract_u = EXTRACT(unsigned int, unsigned, 1);
190 *extract_f = EXTRACT(unsigned int, float, UINT_MAX);
191 break;
192 case GL_FLOAT:
193 *extract_u = EXTRACT(float, unsigned, 1.0 / UINT_MAX);
194 *extract_f = EXTRACT(float, float, 1);
195 break;
196
197 default:
198 assert(0);
199 }
200 }
201
202 /*
203 * Returns a pointer to a chunk of <size> bytes long GART memory. <bo>
204 * will be updated with the buffer object the memory is located in.
205 *
206 * If <offset> is provided, it will be updated with the offset within
207 * <bo> of the allocated memory. Otherwise the returned memory will
208 * always be located right at the beginning of <bo>.
209 */
210 static inline void *
211 get_scratch_vbo(GLcontext *ctx, unsigned size, struct nouveau_bo **bo,
212 unsigned *offset)
213 {
214 struct nouveau_scratch_state *scratch = &to_render_state(ctx)->scratch;
215 void *buf;
216
217 if (scratch->buf && offset &&
218 size <= RENDER_SCRATCH_SIZE - scratch->offset) {
219 nouveau_bo_ref(scratch->bo[scratch->index], bo);
220
221 buf = scratch->buf + scratch->offset;
222 *offset = scratch->offset;
223 scratch->offset += size;
224
225 } else if (size <= RENDER_SCRATCH_SIZE) {
226 scratch->index = (scratch->index + 1) % RENDER_SCRATCH_COUNT;
227 nouveau_bo_ref(scratch->bo[scratch->index], bo);
228
229 nouveau_bo_map(*bo, NOUVEAU_BO_WR);
230 buf = scratch->buf = (*bo)->map;
231 nouveau_bo_unmap(*bo);
232
233 if (offset)
234 *offset = 0;
235 scratch->offset = size;
236
237 } else {
238 nouveau_bo_new(context_dev(ctx),
239 NOUVEAU_BO_MAP | NOUVEAU_BO_GART, 0, size, bo);
240
241 nouveau_bo_map(*bo, NOUVEAU_BO_WR);
242 buf = (*bo)->map;
243 nouveau_bo_unmap(*bo);
244
245 if (offset)
246 *offset = 0;
247 }
248
249 return buf;
250 }
251
252 /*
253 * Returns how many vertices you can draw using <n> pushbuf dwords.
254 */
255 static inline unsigned
256 get_max_vertices(GLcontext *ctx, const struct _mesa_index_buffer *ib,
257 int n)
258 {
259 struct nouveau_render_state *render = to_render_state(ctx);
260
261 if (render->mode == IMM) {
262 return MAX2(0, n - 4) / (render->vertex_size / 4 +
263 render->attr_count);
264 } else {
265 unsigned max_out;
266
267 if (ib) {
268 switch (ib->type) {
269 case GL_UNSIGNED_INT:
270 max_out = MAX_OUT_I32;
271 break;
272
273 case GL_UNSIGNED_SHORT:
274 max_out = MAX_OUT_I16;
275 break;
276
277 case GL_UNSIGNED_BYTE:
278 max_out = MAX_OUT_I16;
279 break;
280 }
281 } else {
282 max_out = MAX_OUT_L;
283 }
284
285 return MAX2(0, n - 7) * max_out * MAX_PACKET / (1 + MAX_PACKET);
286 }
287 }
288
289 #include "nouveau_vbo_t.c"
290 #include "nouveau_swtnl_t.c"
291
292 static void
293 TAG(emit_material)(GLcontext *ctx, struct nouveau_array_state *a,
294 const void *v)
295 {
296 const int attr = a->attr - VERT_ATTRIB_GENERIC0;
297 const int state = ((int []) {
298 NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT,
299 NOUVEAU_STATE_MATERIAL_BACK_AMBIENT,
300 NOUVEAU_STATE_MATERIAL_FRONT_DIFFUSE,
301 NOUVEAU_STATE_MATERIAL_BACK_DIFFUSE,
302 NOUVEAU_STATE_MATERIAL_FRONT_SPECULAR,
303 NOUVEAU_STATE_MATERIAL_BACK_SPECULAR,
304 NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT,
305 NOUVEAU_STATE_MATERIAL_BACK_AMBIENT,
306 NOUVEAU_STATE_MATERIAL_FRONT_SHININESS,
307 NOUVEAU_STATE_MATERIAL_BACK_SHININESS
308 }) [attr];
309
310 COPY_4V(ctx->Light.Material.Attrib[attr], (float *)v);
311 _mesa_update_material(ctx, 1 << attr);
312
313 context_drv(ctx)->emit[state](ctx, state);
314 }
315
316 static void
317 TAG(render_prims)(GLcontext *ctx, const struct gl_client_array **arrays,
318 const struct _mesa_prim *prims, GLuint nr_prims,
319 const struct _mesa_index_buffer *ib,
320 GLboolean index_bounds_valid,
321 GLuint min_index, GLuint max_index)
322 {
323 struct nouveau_context *nctx = to_nouveau_context(ctx);
324
325 nouveau_validate_framebuffer(ctx);
326
327 if (nctx->fallback == HWTNL)
328 TAG(vbo_render_prims)(ctx, arrays, prims, nr_prims, ib,
329 index_bounds_valid, min_index, max_index);
330
331 if (nctx->fallback == SWTNL)
332 _tnl_vbo_draw_prims(ctx, arrays, prims, nr_prims, ib,
333 index_bounds_valid, min_index, max_index);
334 }
335
336 void
337 TAG(render_init)(GLcontext *ctx)
338 {
339 struct nouveau_render_state *render = to_render_state(ctx);
340 struct nouveau_scratch_state *scratch = &render->scratch;
341 int ret, i;
342
343 for (i = 0; i < RENDER_SCRATCH_COUNT; i++) {
344 ret = nouveau_bo_new(context_dev(ctx),
345 NOUVEAU_BO_MAP | NOUVEAU_BO_GART,
346 0, RENDER_SCRATCH_SIZE, &scratch->bo[i]);
347 assert(!ret);
348 }
349
350 for (i = 0; i < VERT_ATTRIB_MAX; i++)
351 render->map[i] = -1;
352
353 TAG(swtnl_init)(ctx);
354 vbo_set_draw_func(ctx, TAG(render_prims));
355 }
356
357 void
358 TAG(render_destroy)(GLcontext *ctx)
359 {
360 TAG(swtnl_destroy)(ctx);
361 }