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.
27 #include "main/bufferobj.h"
28 #include "nouveau_bufferobj.h"
30 /* Arbitrary pushbuf length we can assume we can get with a single
32 #define PUSHBUF_DWORDS 2048
34 /* Functions to set up struct nouveau_array_state from something like
35 * a GL array or index buffer. */
38 vbo_init_array(struct nouveau_array_state
*a
, int attr
, int stride
,
39 int fields
, int type
, struct gl_buffer_object
*obj
,
40 const void *ptr
, GLboolean map
)
47 if (_mesa_is_bufferobj(obj
)) {
48 nouveau_bo_ref(to_nouveau_bufferobj(obj
)->bo
, &a
->bo
);
49 a
->offset
= (intptr_t)ptr
;
52 nouveau_bo_map(a
->bo
, NOUVEAU_BO_RD
);
53 a
->buf
= a
->bo
->map
+ a
->offset
;
59 nouveau_bo_ref(NULL
, &a
->bo
);
65 get_array_extract(a
, &a
->extract_u
, &a
->extract_f
);
69 vbo_deinit_array(struct nouveau_array_state
*a
)
73 nouveau_bo_unmap(a
->bo
);
74 nouveau_bo_ref(NULL
, &a
->bo
);
82 vbo_init_arrays(GLcontext
*ctx
, const struct _mesa_index_buffer
*ib
,
83 const struct gl_client_array
**arrays
)
85 struct nouveau_render_state
*render
= to_render_state(ctx
);
89 vbo_init_array(&render
->ib
, 0, 0, ib
->count
, ib
->type
,
90 ib
->obj
, ib
->ptr
, GL_TRUE
);
92 for (i
= 0; i
< render
->attr_count
; i
++) {
93 int attr
= render
->map
[i
];
96 const struct gl_client_array
*array
= arrays
[attr
];
98 vbo_init_array(&render
->attrs
[attr
], attr
,
99 array
->StrideB
, array
->Size
,
100 array
->Type
, array
->BufferObj
,
101 array
->Ptr
, render
->mode
== IMM
);
107 vbo_deinit_arrays(GLcontext
*ctx
, const struct _mesa_index_buffer
*ib
,
108 const struct gl_client_array
**arrays
)
110 struct nouveau_render_state
*render
= to_render_state(ctx
);
114 vbo_deinit_array(&render
->ib
);
116 for (i
= 0; i
< render
->attr_count
; i
++) {
117 int *attr
= &render
->map
[i
];
120 vbo_deinit_array(&render
->attrs
[*attr
]);
125 render
->attr_count
= 0;
128 /* Make some rendering decisions from the GL context. */
131 vbo_choose_render_mode(GLcontext
*ctx
, const struct gl_client_array
**arrays
)
133 struct nouveau_render_state
*render
= to_render_state(ctx
);
138 if (ctx
->Light
.Enabled
) {
139 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++) {
140 if (arrays
[VERT_ATTRIB_GENERIC0
+ i
]->StrideB
) {
147 if (render
->mode
== VBO
)
148 render
->attr_count
= NUM_VERTEX_ATTRS
;
150 render
->attr_count
= 0;
154 vbo_emit_attr(GLcontext
*ctx
, const struct gl_client_array
**arrays
, int attr
)
156 struct nouveau_channel
*chan
= context_chan(ctx
);
157 struct nouveau_render_state
*render
= to_render_state(ctx
);
158 const struct gl_client_array
*array
= arrays
[attr
];
159 struct nouveau_array_state
*a
= &render
->attrs
[attr
];
162 if (!array
->StrideB
) {
163 if (attr
>= VERT_ATTRIB_GENERIC0
)
164 /* nouveau_update_state takes care of materials. */
167 /* Constant attribute. */
168 vbo_init_array(a
, attr
, array
->StrideB
, array
->Size
,
169 array
->Type
, array
->BufferObj
, array
->Ptr
,
175 /* Varying attribute. */
176 struct nouveau_attr_info
*info
= &TAG(vertex_attrs
)[attr
];
178 if (render
->mode
== VBO
) {
179 render
->map
[info
->vbo_index
] = attr
;
180 render
->vertex_size
+= array
->_ElementSize
;
182 render
->map
[render
->attr_count
++] = attr
;
183 render
->vertex_size
+= 4 * info
->imm_fields
;
188 #define MAT(a) (VERT_ATTRIB_GENERIC0 + MAT_ATTRIB_##a)
191 vbo_choose_attrs(GLcontext
*ctx
, const struct gl_client_array
**arrays
)
193 struct nouveau_render_state
*render
= to_render_state(ctx
);
196 /* Reset the vertex size. */
197 render
->vertex_size
= 0;
199 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_COLOR0
);
200 if (ctx
->Fog
.ColorSumEnabled
&& !ctx
->Light
.Enabled
)
201 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_COLOR1
);
203 for (i
= 0; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
204 if (ctx
->Texture
._EnabledCoordUnits
& (1 << i
))
205 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_TEX0
+ i
);
208 if (ctx
->Fog
.Enabled
&& ctx
->Fog
.FogCoordinateSource
== GL_FOG_COORD
)
209 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_FOG
);
211 if (ctx
->Light
.Enabled
) {
212 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_NORMAL
);
214 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_AMBIENT
));
215 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_DIFFUSE
));
216 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_SPECULAR
));
217 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_SHININESS
));
219 if (ctx
->Light
.Model
.TwoSide
) {
220 vbo_emit_attr(ctx
, arrays
, MAT(BACK_AMBIENT
));
221 vbo_emit_attr(ctx
, arrays
, MAT(BACK_DIFFUSE
));
222 vbo_emit_attr(ctx
, arrays
, MAT(BACK_SPECULAR
));
223 vbo_emit_attr(ctx
, arrays
, MAT(BACK_SHININESS
));
227 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_POS
);
231 TAG(vbo_render_prims
)(GLcontext
*ctx
, const struct gl_client_array
**arrays
,
232 const struct _mesa_prim
*prims
, GLuint nr_prims
,
233 const struct _mesa_index_buffer
*ib
,
234 GLboolean index_bounds_valid
,
235 GLuint min_index
, GLuint max_index
);
238 vbo_maybe_split(GLcontext
*ctx
, const struct gl_client_array
**arrays
,
239 const struct _mesa_prim
*prims
, GLuint nr_prims
,
240 const struct _mesa_index_buffer
*ib
,
241 GLuint min_index
, GLuint max_index
)
243 struct nouveau_context
*nctx
= to_nouveau_context(ctx
);
244 unsigned pushbuf_avail
= PUSHBUF_DWORDS
- 2 * nctx
->bo
.count
,
245 vert_avail
= get_max_vertices(ctx
, NULL
, pushbuf_avail
),
246 idx_avail
= get_max_vertices(ctx
, ib
, pushbuf_avail
);
248 if ((ib
&& ib
->count
> idx_avail
) ||
249 (!ib
&& max_index
- min_index
> vert_avail
)) {
250 struct split_limits limits
= {
251 .max_verts
= vert_avail
,
252 .max_indices
= idx_avail
,
256 vbo_split_prims(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
257 max_index
, TAG(vbo_render_prims
), &limits
);
264 /* VBO rendering path. */
267 vbo_bind_vertices(GLcontext
*ctx
, const struct gl_client_array
**arrays
,
268 GLint basevertex
, GLuint min_index
, GLuint max_index
)
270 struct nouveau_render_state
*render
= to_render_state(ctx
);
273 for (i
= 0; i
< NUM_VERTEX_ATTRS
; i
++) {
274 int attr
= render
->map
[i
];
277 const struct gl_client_array
*array
= arrays
[attr
];
278 struct nouveau_array_state
*a
= &render
->attrs
[attr
];
279 unsigned delta
= (basevertex
+ min_index
) * a
->stride
,
280 size
= (max_index
- min_index
+ 1) * a
->stride
;
283 a
->offset
= (intptr_t)array
->Ptr
+ delta
;
285 void *scratch
= get_scratch_vbo(ctx
, size
,
289 memcpy(scratch
, a
->buf
+ delta
, size
);
294 TAG(render_bind_vertices
)(ctx
);
298 vbo_draw_vbo(GLcontext
*ctx
, const struct gl_client_array
**arrays
,
299 const struct _mesa_prim
*prims
, GLuint nr_prims
,
300 const struct _mesa_index_buffer
*ib
, GLuint min_index
,
303 struct nouveau_channel
*chan
= context_chan(ctx
);
305 int delta
= -min_index
, basevertex
= 0, i
;
308 get_array_dispatch(&to_render_state(ctx
)->ib
, &dispatch
);
310 TAG(render_set_format
)(ctx
);
312 for (i
= 0; i
< nr_prims
; i
++) {
313 unsigned start
= prims
[i
].start
,
314 count
= prims
[i
].count
;
316 if (i
== 0 || basevertex
!= prims
[i
].basevertex
) {
317 basevertex
= prims
[i
].basevertex
;
318 vbo_bind_vertices(ctx
, arrays
, basevertex
,
319 min_index
, max_index
);
322 if (count
> get_max_vertices(ctx
, ib
, chan
->pushbuf
->remaining
))
323 WAIT_RING(chan
, PUSHBUF_DWORDS
);
325 BATCH_BEGIN(nvgl_primitive(prims
[i
].mode
));
326 dispatch(ctx
, start
, delta
, count
);
333 /* Immediate rendering path. */
336 extract_id(struct nouveau_array_state
*a
, int i
, int j
)
342 vbo_draw_imm(GLcontext
*ctx
, const struct gl_client_array
**arrays
,
343 const struct _mesa_prim
*prims
, GLuint nr_prims
,
344 const struct _mesa_index_buffer
*ib
, GLuint min_index
,
347 struct nouveau_render_state
*render
= to_render_state(ctx
);
348 struct nouveau_channel
*chan
= context_chan(ctx
);
349 extract_u_t extract
= ib
? render
->ib
.extract_u
: extract_id
;
353 for (i
= 0; i
< nr_prims
; i
++) {
354 unsigned start
= prims
[i
].start
,
355 end
= start
+ prims
[i
].count
;
357 if (prims
[i
].count
> get_max_vertices(ctx
, ib
,
358 chan
->pushbuf
->remaining
))
359 WAIT_RING(chan
, PUSHBUF_DWORDS
);
361 BATCH_BEGIN(nvgl_primitive(prims
[i
].mode
));
363 for (; start
< end
; start
++) {
364 j
= prims
[i
].basevertex
+
365 extract(&render
->ib
, 0, start
);
367 for (k
= 0; k
< render
->attr_count
; k
++)
368 EMIT_IMM(ctx
, &render
->attrs
[render
->map
[k
]],
378 /* draw_prims entry point when we're doing hw-tnl. */
381 TAG(vbo_render_prims
)(GLcontext
*ctx
, const struct gl_client_array
**arrays
,
382 const struct _mesa_prim
*prims
, GLuint nr_prims
,
383 const struct _mesa_index_buffer
*ib
,
384 GLboolean index_bounds_valid
,
385 GLuint min_index
, GLuint max_index
)
387 struct nouveau_render_state
*render
= to_render_state(ctx
);
389 if (!index_bounds_valid
)
390 vbo_get_minmax_index(ctx
, prims
, ib
, &min_index
, &max_index
);
392 vbo_choose_render_mode(ctx
, arrays
);
393 vbo_choose_attrs(ctx
, arrays
);
395 if (vbo_maybe_split(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
399 vbo_init_arrays(ctx
, ib
, arrays
);
401 if (render
->mode
== VBO
)
402 vbo_draw_vbo(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
405 vbo_draw_imm(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
408 vbo_deinit_arrays(ctx
, ib
, arrays
);