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 "nouveau_driver.h"
28 #include "nouveau_bufferobj.h"
29 #include "nouveau_util.h"
31 #include "main/bufferobj.h"
32 #include "main/glformats.h"
33 #include "main/image.h"
35 /* Arbitrary pushbuf length we can assume we can get with a single
36 * call to WAIT_RING. */
37 #define PUSHBUF_DWORDS 65536
39 /* Functions to turn GL arrays or index buffers into nouveau_array
43 get_array_stride(struct gl_context
*ctx
, const struct gl_vertex_array
*a
)
45 struct nouveau_render_state
*render
= to_render_state(ctx
);
47 if (render
->mode
== VBO
&& !_mesa_is_bufferobj(a
->BufferObj
))
48 /* Pack client buffers. */
49 return align(_mesa_sizeof_type(a
->Type
) * a
->Size
, 4);
55 vbo_init_arrays(struct gl_context
*ctx
, const struct _mesa_index_buffer
*ib
,
56 const struct gl_vertex_array
**arrays
)
58 struct nouveau_render_state
*render
= to_render_state(ctx
);
59 GLboolean imm
= (render
->mode
== IMM
);
65 if (ib
->index_size
== 4)
66 ib_type
= GL_UNSIGNED_INT
;
67 else if (ib
->index_size
== 2)
68 ib_type
= GL_UNSIGNED_SHORT
;
70 ib_type
= GL_UNSIGNED_BYTE
;
72 nouveau_init_array(&render
->ib
, 0, 0, ib
->count
, ib_type
,
73 ib
->obj
, ib
->ptr
, GL_TRUE
, ctx
);
76 FOR_EACH_BOUND_ATTR(render
, i
, attr
) {
77 const struct gl_vertex_array
*array
= arrays
[attr
];
79 nouveau_init_array(&render
->attrs
[attr
], attr
,
80 get_array_stride(ctx
, array
),
81 array
->Size
, array
->Type
,
82 imm
? array
->BufferObj
: NULL
,
83 array
->Ptr
, imm
, ctx
);
88 vbo_deinit_arrays(struct gl_context
*ctx
, const struct _mesa_index_buffer
*ib
,
89 const struct gl_vertex_array
**arrays
)
91 struct nouveau_render_state
*render
= to_render_state(ctx
);
95 nouveau_cleanup_array(&render
->ib
);
97 FOR_EACH_BOUND_ATTR(render
, i
, attr
) {
98 struct nouveau_array
*a
= &render
->attrs
[attr
];
100 if (render
->mode
== IMM
)
101 nouveau_bo_ref(NULL
, &a
->bo
);
103 nouveau_deinit_array(a
);
107 render
->attr_count
= 0;
110 /* Make some rendering decisions from the GL context. */
113 vbo_choose_render_mode(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
)
115 struct nouveau_render_state
*render
= to_render_state(ctx
);
120 if (ctx
->Light
.Enabled
) {
121 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++) {
122 if (arrays
[VERT_ATTRIB_GENERIC0
+ i
]->StrideB
) {
131 vbo_emit_attr(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
,
134 struct nouveau_pushbuf
*push
= context_push(ctx
);
135 struct nouveau_render_state
*render
= to_render_state(ctx
);
136 const struct gl_vertex_array
*array
= arrays
[attr
];
137 struct nouveau_array
*a
= &render
->attrs
[attr
];
140 if (!array
->StrideB
) {
141 if (attr
>= VERT_ATTRIB_GENERIC0
)
142 /* nouveau_update_state takes care of materials. */
145 /* Constant attribute. */
146 nouveau_init_array(a
, attr
, array
->StrideB
, array
->Size
,
147 array
->Type
, array
->BufferObj
, array
->Ptr
,
150 nouveau_deinit_array(a
);
153 /* Varying attribute. */
154 struct nouveau_attr_info
*info
= &TAG(vertex_attrs
)[attr
];
156 if (render
->mode
== VBO
) {
157 render
->map
[info
->vbo_index
] = attr
;
158 render
->vertex_size
+= array
->_ElementSize
;
159 render
->attr_count
= MAX2(render
->attr_count
,
160 info
->vbo_index
+ 1);
162 render
->map
[render
->attr_count
++] = attr
;
163 render
->vertex_size
+= 4 * info
->imm_fields
;
168 #define MAT(a) (VERT_ATTRIB_GENERIC0 + MAT_ATTRIB_##a)
171 vbo_choose_attrs(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
)
173 struct nouveau_render_state
*render
= to_render_state(ctx
);
176 /* Reset the vertex size. */
177 render
->vertex_size
= 0;
178 render
->attr_count
= 0;
180 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_COLOR0
);
181 if (ctx
->Fog
.ColorSumEnabled
&& !ctx
->Light
.Enabled
)
182 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_COLOR1
);
184 for (i
= 0; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
185 if (ctx
->Texture
._EnabledCoordUnits
& (1 << i
))
186 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_TEX0
+ i
);
189 if (ctx
->Fog
.Enabled
&& ctx
->Fog
.FogCoordinateSource
== GL_FOG_COORD
)
190 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_FOG
);
192 if (ctx
->Light
.Enabled
||
193 (ctx
->Texture
._GenFlags
& TEXGEN_NEED_NORMALS
))
194 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_NORMAL
);
196 if (ctx
->Light
.Enabled
&& render
->mode
== IMM
) {
197 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_AMBIENT
));
198 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_DIFFUSE
));
199 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_SPECULAR
));
200 vbo_emit_attr(ctx
, arrays
, MAT(FRONT_SHININESS
));
202 if (ctx
->Light
.Model
.TwoSide
) {
203 vbo_emit_attr(ctx
, arrays
, MAT(BACK_AMBIENT
));
204 vbo_emit_attr(ctx
, arrays
, MAT(BACK_DIFFUSE
));
205 vbo_emit_attr(ctx
, arrays
, MAT(BACK_SPECULAR
));
206 vbo_emit_attr(ctx
, arrays
, MAT(BACK_SHININESS
));
210 vbo_emit_attr(ctx
, arrays
, VERT_ATTRIB_POS
);
214 get_max_client_stride(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
)
216 struct nouveau_render_state
*render
= to_render_state(ctx
);
219 FOR_EACH_BOUND_ATTR(render
, i
, attr
) {
220 const struct gl_vertex_array
*a
= arrays
[attr
];
222 if (!_mesa_is_bufferobj(a
->BufferObj
))
223 s
= MAX2(s
, get_array_stride(ctx
, a
));
230 TAG(vbo_render_prims
)(struct gl_context
*ctx
,
231 const struct _mesa_prim
*prims
, GLuint nr_prims
,
232 const struct _mesa_index_buffer
*ib
,
233 GLboolean index_bounds_valid
,
234 GLuint min_index
, GLuint max_index
,
235 struct gl_transform_feedback_object
*tfb_vertcount
,
237 struct gl_buffer_object
*indirect
);
240 vbo_maybe_split(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
,
241 const struct _mesa_prim
*prims
, GLuint nr_prims
,
242 const struct _mesa_index_buffer
*ib
,
243 GLuint min_index
, GLuint max_index
)
245 struct nouveau_context
*nctx
= to_nouveau_context(ctx
);
246 struct nouveau_render_state
*render
= to_render_state(ctx
);
247 struct nouveau_bufctx
*bufctx
= nctx
->hw
.bufctx
;
248 unsigned pushbuf_avail
= PUSHBUF_DWORDS
- 2 * (bufctx
->relocs
+
250 vert_avail
= get_max_vertices(ctx
, NULL
, pushbuf_avail
),
251 idx_avail
= get_max_vertices(ctx
, ib
, pushbuf_avail
);
254 /* Try to keep client buffers smaller than the scratch BOs. */
255 if (render
->mode
== VBO
&&
256 (stride
= get_max_client_stride(ctx
, arrays
)))
257 vert_avail
= MIN2(vert_avail
,
258 NOUVEAU_SCRATCH_SIZE
/ stride
);
260 if (max_index
- min_index
> vert_avail
||
261 (ib
&& ib
->count
> idx_avail
)) {
262 struct split_limits limits
= {
263 .max_verts
= vert_avail
,
264 .max_indices
= idx_avail
,
268 vbo_split_prims(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
269 max_index
, TAG(vbo_render_prims
), &limits
);
276 /* VBO rendering path. */
279 check_update_array(struct nouveau_array
*a
, unsigned offset
,
280 struct nouveau_bo
*bo
, int *pdelta
)
287 delta
= ((int)offset
- (int)a
->offset
) / a
->stride
;
289 dirty
= (delta
< 0 ||
290 offset
!= (a
->offset
+ delta
* a
->stride
));
295 *pdelta
= (dirty
? 0 : delta
);
300 vbo_bind_vertices(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
,
301 int base
, unsigned min_index
, unsigned max_index
, int *pdelta
)
303 struct nouveau_render_state
*render
= to_render_state(ctx
);
304 struct nouveau_pushbuf
*push
= context_push(ctx
);
305 struct nouveau_bo
*bo
[NUM_VERTEX_ATTRS
];
306 unsigned offset
[NUM_VERTEX_ATTRS
];
307 GLboolean dirty
= GL_FALSE
;
313 FOR_EACH_BOUND_ATTR(render
, i
, attr
) {
314 const struct gl_vertex_array
*array
= arrays
[attr
];
315 struct gl_buffer_object
*obj
= array
->BufferObj
;
316 struct nouveau_array
*a
= &render
->attrs
[attr
];
317 unsigned delta
= (base
+ min_index
) * array
->StrideB
;
321 if (nouveau_bufferobj_hw(obj
)) {
322 /* Array in a buffer obj. */
323 nouveau_bo_ref(to_nouveau_bufferobj(obj
)->bo
, &bo
[i
]);
324 offset
[i
] = delta
+ (intptr_t)array
->Ptr
;
327 int n
= max_index
- min_index
+ 1;
328 char *sp
= (char *)ADD_POINTERS(
329 nouveau_bufferobj_sys(obj
), array
->Ptr
) + delta
;
330 char *dp
= nouveau_get_scratch(ctx
, n
* a
->stride
,
333 /* Array in client memory, move it to a
334 * scratch buffer obj. */
335 for (j
= 0; j
< n
; j
++)
336 memcpy(dp
+ j
* a
->stride
,
337 sp
+ j
* array
->StrideB
,
341 dirty
|= check_update_array(a
, offset
[i
], bo
[i
], pdelta
);
344 *pdelta
-= min_index
;
347 /* Buffers changed, update the attribute binding. */
348 FOR_EACH_BOUND_ATTR(render
, i
, attr
) {
349 struct nouveau_array
*a
= &render
->attrs
[attr
];
351 nouveau_bo_ref(NULL
, &a
->bo
);
352 a
->offset
= offset
[i
];
356 TAG(render_release_vertices
)(ctx
);
357 TAG(render_bind_vertices
)(ctx
);
360 FOR_EACH_BOUND_ATTR(render
, i
, attr
)
361 nouveau_bo_ref(NULL
, &bo
[i
]);
368 vbo_draw_vbo(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
,
369 const struct _mesa_prim
*prims
, GLuint nr_prims
,
370 const struct _mesa_index_buffer
*ib
, GLuint min_index
,
373 struct nouveau_context
*nctx
= to_nouveau_context(ctx
);
374 struct nouveau_pushbuf
*push
= context_push(ctx
);
375 dispatch_t dispatch
= get_array_dispatch(&to_render_state(ctx
)->ib
);
376 int i
, delta
= 0, basevertex
= 0;
379 TAG(render_set_format
)(ctx
);
381 for (i
= 0; i
< nr_prims
; i
++) {
382 unsigned start
= prims
[i
].start
,
383 count
= prims
[i
].count
;
385 if (i
== 0 || basevertex
!= prims
[i
].basevertex
) {
386 basevertex
= prims
[i
].basevertex
;
387 vbo_bind_vertices(ctx
, arrays
, basevertex
, min_index
,
390 nouveau_pushbuf_bufctx(push
, nctx
->hw
.bufctx
);
391 if (nouveau_pushbuf_validate(push
)) {
392 nouveau_pushbuf_bufctx(push
, NULL
);
397 if (count
> get_max_vertices(ctx
, ib
, PUSH_AVAIL(push
)))
398 PUSH_SPACE(push
, PUSHBUF_DWORDS
);
400 BATCH_BEGIN(nvgl_primitive(prims
[i
].mode
));
401 dispatch(ctx
, start
, delta
, count
);
405 nouveau_pushbuf_bufctx(push
, NULL
);
406 TAG(render_release_vertices
)(ctx
);
409 /* Immediate rendering path. */
412 extract_id(struct nouveau_array
*a
, int i
, int j
)
418 vbo_draw_imm(struct gl_context
*ctx
, const struct gl_vertex_array
**arrays
,
419 const struct _mesa_prim
*prims
, GLuint nr_prims
,
420 const struct _mesa_index_buffer
*ib
, GLuint min_index
,
423 struct nouveau_render_state
*render
= to_render_state(ctx
);
424 struct nouveau_context
*nctx
= to_nouveau_context(ctx
);
425 struct nouveau_pushbuf
*push
= context_push(ctx
);
426 extract_u_t extract
= ib
? render
->ib
.extract_u
: extract_id
;
430 nouveau_pushbuf_bufctx(push
, nctx
->hw
.bufctx
);
431 if (nouveau_pushbuf_validate(push
)) {
432 nouveau_pushbuf_bufctx(push
, NULL
);
436 for (i
= 0; i
< nr_prims
; i
++) {
437 unsigned start
= prims
[i
].start
,
438 end
= start
+ prims
[i
].count
;
440 if (prims
[i
].count
> get_max_vertices(ctx
, ib
,
442 PUSH_SPACE(push
, PUSHBUF_DWORDS
);
444 BATCH_BEGIN(nvgl_primitive(prims
[i
].mode
));
446 for (; start
< end
; start
++) {
447 j
= prims
[i
].basevertex
+
448 extract(&render
->ib
, 0, start
);
450 FOR_EACH_BOUND_ATTR(render
, k
, attr
)
451 EMIT_IMM(ctx
, &render
->attrs
[attr
], j
);
457 nouveau_pushbuf_bufctx(push
, NULL
);
460 /* draw_prims entry point when we're doing hw-tnl. */
463 TAG(vbo_render_prims
)(struct gl_context
*ctx
,
464 const struct _mesa_prim
*prims
, GLuint nr_prims
,
465 const struct _mesa_index_buffer
*ib
,
466 GLboolean index_bounds_valid
,
467 GLuint min_index
, GLuint max_index
,
468 struct gl_transform_feedback_object
*tfb_vertcount
,
470 struct gl_buffer_object
*indirect
)
472 struct nouveau_render_state
*render
= to_render_state(ctx
);
473 const struct gl_vertex_array
**arrays
= ctx
->Array
._DrawArrays
;
475 if (!index_bounds_valid
)
476 vbo_get_minmax_indices(ctx
, prims
, ib
, &min_index
, &max_index
,
479 vbo_choose_render_mode(ctx
, arrays
);
480 vbo_choose_attrs(ctx
, arrays
);
482 if (vbo_maybe_split(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
486 vbo_init_arrays(ctx
, ib
, arrays
);
488 if (render
->mode
== VBO
)
489 vbo_draw_vbo(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
492 vbo_draw_imm(ctx
, arrays
, prims
, nr_prims
, ib
, min_index
,
495 vbo_deinit_arrays(ctx
, ib
, arrays
);
498 /* VBO rendering entry points. */
501 TAG(vbo_check_render_prims
)(struct gl_context
*ctx
,
502 const struct _mesa_prim
*prims
, GLuint nr_prims
,
503 const struct _mesa_index_buffer
*ib
,
504 GLboolean index_bounds_valid
,
505 GLuint min_index
, GLuint max_index
,
506 struct gl_transform_feedback_object
*tfb_vertcount
,
508 struct gl_buffer_object
*indirect
)
510 struct nouveau_context
*nctx
= to_nouveau_context(ctx
);
512 nouveau_validate_framebuffer(ctx
);
514 if (nctx
->fallback
== HWTNL
)
515 TAG(vbo_render_prims
)(ctx
, prims
, nr_prims
, ib
,
516 index_bounds_valid
, min_index
, max_index
,
517 tfb_vertcount
, stream
, indirect
);
519 if (nctx
->fallback
== SWTNL
)
520 _tnl_draw_prims(ctx
, prims
, nr_prims
, ib
,
521 index_bounds_valid
, min_index
, max_index
,
522 tfb_vertcount
, stream
, indirect
);
526 TAG(vbo_init
)(struct gl_context
*ctx
)
528 struct nouveau_render_state
*render
= to_render_state(ctx
);
531 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
534 vbo_set_draw_func(ctx
, TAG(vbo_check_render_prims
));
535 vbo_use_buffer_objects(ctx
);
539 TAG(vbo_destroy
)(struct gl_context
*ctx
)