2 * Copyright (C) 2009-2010 Francisco Jerez.
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:
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.
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.
28 * Vertex submission helper definitions shared among the software and
32 #include "nouveau_gldefs.h"
34 #include "main/light.h"
38 #define OUT_INDICES_L(r, i, d, n) \
39 BATCH_OUT_L(i + d, n); \
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)
48 * Emit <n> vertices using BATCH_OUT_<out>, MAX_OUT_<out> at a time,
49 * grouping them in packets of length MAX_PACKET.
51 * out: hardware index data type.
53 * start: element within the index buffer to begin with.
54 * delta: integer correction that will be added to each index found in
57 #define EMIT_VBO(out, ctx, start, delta, n) do { \
58 struct nouveau_render_state *render = to_render_state(ctx); \
62 int npack = MIN2(npush, MAX_PACKET * MAX_OUT_##out); \
65 BATCH_PACKET_##out((npack + MAX_OUT_##out - 1) \
68 int nout = MIN2(npack, MAX_OUT_##out); \
71 OUT_INDICES_##out(render, start, delta, \
79 * Emit the <n>-th element of the array <a>, using IMM_OUT.
81 #define EMIT_IMM(ctx, a, n) do { \
82 struct nouveau_attr_info *info = \
83 &TAG(vertex_attrs)[(a)->attr]; \
87 IMM_PACKET(info->imm_method, info->imm_fields); \
89 for (m = 0; m < (a)->fields; m++) \
90 IMM_OUT((a)->extract_f(a, n, m)); \
92 for (m = (a)->fields; m < info->imm_fields; m++) \
93 IMM_OUT(((float []){0, 0, 0, 1})[m]); \
96 info->emit(ctx, a, (a)->buf + n * (a)->stride); \
101 * Select an appropriate dispatch function for the given index buffer.
104 get_array_dispatch(struct nouveau_array_state
*a
, dispatch_t
*dispatch
)
107 auto void f(GLcontext
*, unsigned int, int, unsigned int);
109 void f(GLcontext
*ctx
, unsigned int start
, int delta
,
111 struct nouveau_channel
*chan
= context_chan(ctx
);
114 EMIT_VBO(L
, ctx
, start
, delta
, n
);
119 } else if (a
->type
== GL_UNSIGNED_INT
) {
120 auto void f(GLcontext
*, unsigned int, int, unsigned int);
122 void f(GLcontext
*ctx
, unsigned int start
, int delta
,
124 struct nouveau_channel
*chan
= context_chan(ctx
);
127 EMIT_VBO(I32
, ctx
, start
, delta
, n
);
133 auto void f(GLcontext
*, unsigned int, int, unsigned int);
135 void f(GLcontext
*ctx
, unsigned int start
, int delta
,
137 struct nouveau_channel
*chan
= context_chan(ctx
);
140 EMIT_VBO(I32
, ctx
, start
, delta
, n
& 1);
141 EMIT_VBO(I16
, ctx
, start
, delta
, n
& ~1);
149 * Select appropriate element extraction functions for the given
153 get_array_extract(struct nouveau_array_state
*a
,
154 extract_u_t
*extract_u
, extract_f_t
*extract_f
)
156 #define EXTRACT(in_t, out_t, k) \
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]; \
162 return (out_t)x / (k); \
169 *extract_u
= EXTRACT(char, unsigned, 1);
170 *extract_f
= EXTRACT(char, float, SCHAR_MAX
);
172 case GL_UNSIGNED_BYTE
:
173 *extract_u
= EXTRACT(unsigned char, unsigned, 1);
174 *extract_f
= EXTRACT(unsigned char, float, UCHAR_MAX
);
177 *extract_u
= EXTRACT(short, unsigned, 1);
178 *extract_f
= EXTRACT(short, float, SHRT_MAX
);
180 case GL_UNSIGNED_SHORT
:
181 *extract_u
= EXTRACT(unsigned short, unsigned, 1);
182 *extract_f
= EXTRACT(unsigned short, float, USHRT_MAX
);
185 *extract_u
= EXTRACT(int, unsigned, 1);
186 *extract_f
= EXTRACT(int, float, INT_MAX
);
188 case GL_UNSIGNED_INT
:
189 *extract_u
= EXTRACT(unsigned int, unsigned, 1);
190 *extract_f
= EXTRACT(unsigned int, float, UINT_MAX
);
193 *extract_u
= EXTRACT(float, unsigned, 1.0 / UINT_MAX
);
194 *extract_f
= EXTRACT(float, float, 1);
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.
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>.
211 get_scratch_vbo(GLcontext
*ctx
, unsigned size
, struct nouveau_bo
**bo
,
214 struct nouveau_scratch_state
*scratch
= &to_render_state(ctx
)->scratch
;
217 if (scratch
->buf
&& offset
&&
218 size
<= RENDER_SCRATCH_SIZE
- scratch
->offset
) {
219 nouveau_bo_ref(scratch
->bo
[scratch
->index
], bo
);
221 buf
= scratch
->buf
+ scratch
->offset
;
222 *offset
= scratch
->offset
;
223 scratch
->offset
+= size
;
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
);
229 nouveau_bo_map(*bo
, NOUVEAU_BO_WR
);
230 buf
= scratch
->buf
= (*bo
)->map
;
231 nouveau_bo_unmap(*bo
);
235 scratch
->offset
= size
;
238 nouveau_bo_new(context_dev(ctx
),
239 NOUVEAU_BO_MAP
| NOUVEAU_BO_GART
, 0, size
, bo
);
241 nouveau_bo_map(*bo
, NOUVEAU_BO_WR
);
243 nouveau_bo_unmap(*bo
);
253 * Returns how many vertices you can draw using <n> pushbuf dwords.
255 static inline unsigned
256 get_max_vertices(GLcontext
*ctx
, const struct _mesa_index_buffer
*ib
,
259 struct nouveau_render_state
*render
= to_render_state(ctx
);
261 if (render
->mode
== IMM
) {
262 return MAX2(0, n
- 4) / (render
->vertex_size
/ 4 +
269 case GL_UNSIGNED_INT
:
270 max_out
= MAX_OUT_I32
;
273 case GL_UNSIGNED_SHORT
:
274 max_out
= MAX_OUT_I16
;
277 case GL_UNSIGNED_BYTE
:
278 max_out
= MAX_OUT_I16
;
285 return MAX2(0, n
- 7) * max_out
* MAX_PACKET
/ (1 + MAX_PACKET
);
289 #include "nouveau_vbo_t.c"
290 #include "nouveau_swtnl_t.c"
293 TAG(emit_material
)(GLcontext
*ctx
, struct nouveau_array_state
*a
,
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
310 COPY_4V(ctx
->Light
.Material
.Attrib
[attr
], (float *)v
);
311 _mesa_update_material(ctx
, 1 << attr
);
313 context_drv(ctx
)->emit
[state
](ctx
, state
);
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
)
323 struct nouveau_context
*nctx
= to_nouveau_context(ctx
);
325 nouveau_validate_framebuffer(ctx
);
327 if (nctx
->fallback
== HWTNL
)
328 TAG(vbo_render_prims
)(ctx
, arrays
, prims
, nr_prims
, ib
,
329 index_bounds_valid
, min_index
, max_index
);
331 if (nctx
->fallback
== SWTNL
)
332 _tnl_vbo_draw_prims(ctx
, arrays
, prims
, nr_prims
, ib
,
333 index_bounds_valid
, min_index
, max_index
);
337 TAG(render_init
)(GLcontext
*ctx
)
339 struct nouveau_render_state
*render
= to_render_state(ctx
);
340 struct nouveau_scratch_state
*scratch
= &render
->scratch
;
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
]);
350 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
353 TAG(swtnl_init
)(ctx
);
354 vbo_set_draw_func(ctx
, TAG(render_prims
));
358 TAG(render_destroy
)(GLcontext
*ctx
)
360 TAG(swtnl_destroy
)(ctx
);