Tizen 2.0 Release
[profile/ivi/osmesa.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 dispatch_t
104 get_array_dispatch(struct nouveau_array *a)
105 {
106         if (!a->fields) {
107                 auto void f(struct gl_context *, unsigned int, int, unsigned int);
108
109                 void f(struct gl_context *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                 return f;
118
119         } else if (a->type == GL_UNSIGNED_INT) {
120                 auto void f(struct gl_context *, unsigned int, int, unsigned int);
121
122                 void f(struct gl_context *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                 return f;
131
132         } else {
133                 auto void f(struct gl_context *, unsigned int, int, unsigned int);
134
135                 void f(struct gl_context *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                 return f;
145         }
146 }
147
148 /*
149  * Returns how many vertices you can draw using <n> pushbuf dwords.
150  */
151 static inline unsigned
152 get_max_vertices(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
153                  int n)
154 {
155         struct nouveau_render_state *render = to_render_state(ctx);
156
157         if (render->mode == IMM) {
158                 return MAX2(0, n - 4) / (render->vertex_size / 4 +
159                                          render->attr_count);
160         } else {
161                 unsigned max_out;
162
163                 if (ib) {
164                         switch (ib->type) {
165                         case GL_UNSIGNED_INT:
166                                 max_out = MAX_OUT_I32;
167                                 break;
168
169                         case GL_UNSIGNED_SHORT:
170                                 max_out = MAX_OUT_I16;
171                                 break;
172
173                         case GL_UNSIGNED_BYTE:
174                                 max_out = MAX_OUT_I16;
175                                 break;
176
177                         default:
178                                 assert(0);
179                                 max_out = 0;
180                                 break;
181                         }
182                 } else {
183                         max_out = MAX_OUT_L;
184                 }
185
186                 return MAX2(0, n - 7) * max_out * MAX_PACKET / (1 + MAX_PACKET);
187         }
188 }
189
190 static void
191 TAG(emit_material)(struct gl_context *ctx, struct nouveau_array *a,
192                    const void *v)
193 {
194         int attr = a->attr - VERT_ATTRIB_GENERIC0;
195         int state = ((int []) {
196                         NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT,
197                         NOUVEAU_STATE_MATERIAL_BACK_AMBIENT,
198                         NOUVEAU_STATE_MATERIAL_FRONT_DIFFUSE,
199                         NOUVEAU_STATE_MATERIAL_BACK_DIFFUSE,
200                         NOUVEAU_STATE_MATERIAL_FRONT_SPECULAR,
201                         NOUVEAU_STATE_MATERIAL_BACK_SPECULAR,
202                         NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT,
203                         NOUVEAU_STATE_MATERIAL_BACK_AMBIENT,
204                         NOUVEAU_STATE_MATERIAL_FRONT_SHININESS,
205                         NOUVEAU_STATE_MATERIAL_BACK_SHININESS
206                 }) [attr];
207
208         COPY_4V(ctx->Light.Material.Attrib[attr], (float *)v);
209         _mesa_update_material(ctx, 1 << attr);
210
211         context_drv(ctx)->emit[state](ctx, state);
212 }