struct cso_context {
struct pipe_context *pipe;
struct cso_cache *cache;
+
struct u_vbuf *vbuf;
+ struct u_vbuf *vbuf_current;
+ bool always_use_vbuf;
boolean has_geometry_shader;
boolean has_tessellation;
(uses_user_vertex_buffers &&
caps.fallback_only_for_user_vbuffers)) {
cso->vbuf = u_vbuf_create(cso->pipe, &caps);
+ cso->vbuf_current = cso->vbuf;
+ cso->always_use_vbuf = caps.fallback_always;
}
}
unsigned count,
const struct pipe_vertex_element *states)
{
- struct u_vbuf *vbuf = ctx->vbuf;
+ struct u_vbuf *vbuf = ctx->vbuf_current;
if (vbuf) {
u_vbuf_set_vertex_elements(vbuf, count, states);
static void
cso_save_vertex_elements(struct cso_context *ctx)
{
- struct u_vbuf *vbuf = ctx->vbuf;
+ struct u_vbuf *vbuf = ctx->vbuf_current;
if (vbuf) {
u_vbuf_save_vertex_elements(vbuf);
static void
cso_restore_vertex_elements(struct cso_context *ctx)
{
- struct u_vbuf *vbuf = ctx->vbuf;
+ struct u_vbuf *vbuf = ctx->vbuf_current;
if (vbuf) {
u_vbuf_restore_vertex_elements(vbuf);
unsigned start_slot, unsigned count,
const struct pipe_vertex_buffer *buffers)
{
- struct u_vbuf *vbuf = ctx->vbuf;
+ struct u_vbuf *vbuf = ctx->vbuf_current;
if (!count)
return;
static void
cso_save_vertex_buffer0(struct cso_context *ctx)
{
- struct u_vbuf *vbuf = ctx->vbuf;
+ struct u_vbuf *vbuf = ctx->vbuf_current;
if (vbuf) {
u_vbuf_save_vertex_buffer0(vbuf);
static void
cso_restore_vertex_buffer0(struct cso_context *ctx)
{
- struct u_vbuf *vbuf = ctx->vbuf;
+ struct u_vbuf *vbuf = ctx->vbuf_current;
if (vbuf) {
u_vbuf_restore_vertex_buffer0(vbuf);
pipe_vertex_buffer_unreference(&ctx->vertex_buffer0_saved);
}
+/**
+ * Set vertex buffers and vertex elements. Skip u_vbuf if it's only needed
+ * for user vertex buffers and user vertex buffers are not set by this call.
+ * u_vbuf will be disabled. To re-enable u_vbuf, call this function again.
+ *
+ * Skipping u_vbuf decreases CPU overhead for draw calls that don't need it,
+ * such as VBOs, glBegin/End, and display lists.
+ *
+ * Internal operations that do "save states, draw, restore states" shouldn't
+ * use this, because the states are only saved in either cso_context or
+ * u_vbuf, not both.
+ */
+void
+cso_set_vertex_buffers_and_elements(struct cso_context *ctx,
+ unsigned velem_count,
+ const struct pipe_vertex_element *velems,
+ unsigned vb_count,
+ unsigned unbind_trailing_vb_count,
+ const struct pipe_vertex_buffer *vbuffers,
+ bool uses_user_vertex_buffers)
+{
+ struct u_vbuf *vbuf = ctx->vbuf;
+
+ if (vbuf && (ctx->always_use_vbuf || uses_user_vertex_buffers)) {
+ if (!ctx->vbuf_current) {
+ /* Unbind all buffers in cso_context, because we'll use u_vbuf. */
+ unsigned unbind_vb_count = vb_count + unbind_trailing_vb_count;
+ if (unbind_vb_count)
+ cso_set_vertex_buffers_direct(ctx, 0, unbind_vb_count, NULL);
+
+ /* Unset this to make sure the CSO is re-bound on the next use. */
+ ctx->velements = NULL;
+ ctx->vbuf_current = vbuf;
+ } else if (unbind_trailing_vb_count) {
+ u_vbuf_set_vertex_buffers(vbuf, vb_count, unbind_trailing_vb_count,
+ NULL);
+ }
+
+ if (vb_count)
+ u_vbuf_set_vertex_buffers(vbuf, 0, vb_count, vbuffers);
+ u_vbuf_set_vertex_elements(vbuf, velem_count, velems);
+ return;
+ }
+
+ if (ctx->vbuf_current) {
+ /* Unbind all buffers in u_vbuf, because we'll use cso_context. */
+ unsigned unbind_vb_count = vb_count + unbind_trailing_vb_count;
+ if (unbind_vb_count)
+ u_vbuf_set_vertex_buffers(vbuf, 0, unbind_vb_count, NULL);
+
+ /* Unset this to make sure the CSO is re-bound on the next use. */
+ u_vbuf_unset_vertex_elements(vbuf);
+ ctx->vbuf_current = NULL;
+ } else if (unbind_trailing_vb_count) {
+ cso_set_vertex_buffers_direct(ctx, vb_count, unbind_trailing_vb_count,
+ NULL);
+ }
+
+ if (vb_count)
+ cso_set_vertex_buffers_direct(ctx, 0, vb_count, vbuffers);
+ cso_set_vertex_elements_direct(ctx, velem_count, velems);
+}
void
cso_single_sampler(struct cso_context *ctx, enum pipe_shader_type shader_stage,
cso_draw_vbo(struct cso_context *cso,
const struct pipe_draw_info *info)
{
- struct u_vbuf *vbuf = cso->vbuf;
+ struct u_vbuf *vbuf = cso->vbuf_current;
/* We can't have both indirect drawing and SO-vertex-count drawing */
assert(info->indirect == NULL || info->count_from_stream_output == NULL);
void cso_restore_constant_buffer_slot0(struct cso_context *cso,
enum pipe_shader_type shader_stage);
+/* Optimized version. */
+void
+cso_set_vertex_buffers_and_elements(struct cso_context *ctx,
+ unsigned velem_count,
+ const struct pipe_vertex_element *velems,
+ unsigned vb_count,
+ unsigned unbind_trailing_vb_count,
+ const struct pipe_vertex_buffer *vbuffers,
+ bool uses_user_vertex_buffers);
/* drawing */
mgr->ve = u_vbuf_set_vertex_elements_internal(mgr, count, states);
}
+void u_vbuf_unset_vertex_elements(struct u_vbuf *mgr)
+{
+ mgr->ve = NULL;
+}
+
void u_vbuf_destroy(struct u_vbuf *mgr)
{
struct pipe_screen *screen = mgr->pipe->screen;
/* State and draw functions. */
void u_vbuf_set_vertex_elements(struct u_vbuf *mgr, unsigned count,
const struct pipe_vertex_element *states);
+void u_vbuf_unset_vertex_elements(struct u_vbuf *mgr);
void u_vbuf_set_vertex_buffers(struct u_vbuf *mgr,
unsigned start_slot, unsigned count,
const struct pipe_vertex_buffer *bufs);
const struct st_vertex_program *vp,
const struct st_common_variant *vp_variant,
struct pipe_vertex_element *velements,
- struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers);
+ struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers,
+ bool *has_user_vertex_buffers);
void
st_setup_current(struct st_context *st,
}
}
-static void
-set_vertex_attribs(struct st_context *st,
- struct pipe_vertex_buffer *vbuffers,
- unsigned num_vbuffers,
- struct pipe_vertex_element *velements,
- unsigned num_velements)
-{
- struct cso_context *cso = st->cso_context;
-
- cso_set_vertex_buffers(cso, 0, num_vbuffers, vbuffers);
- if (st->last_num_vbuffers > num_vbuffers) {
- /* Unbind remaining buffers, if any. */
- cso_set_vertex_buffers(cso, num_vbuffers,
- st->last_num_vbuffers - num_vbuffers, NULL);
- }
- st->last_num_vbuffers = num_vbuffers;
- cso_set_vertex_elements(cso, num_velements, velements);
-}
-
void
st_setup_arrays(struct st_context *st,
const struct st_vertex_program *vp,
const struct st_common_variant *vp_variant,
struct pipe_vertex_element *velements,
- struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers)
+ struct pipe_vertex_buffer *vbuffer, unsigned *num_vbuffers,
+ bool *has_user_vertex_buffers)
{
struct gl_context *ctx = st->ctx;
const struct gl_vertex_array_object *vao = ctx->Array._DrawVAO;
const GLbitfield inputs_read = vp_variant->vert_attrib_mask;
const ubyte *input_to_index = vp->input_to_index;
+ bool uses_user_vertex_buffers = false;
/* Process attribute array data. */
GLbitfield mask = inputs_read & _mesa_draw_array_bits(ctx);
vbuffer[bufidx].is_user_buffer = true;
vbuffer[bufidx].buffer_offset = 0;
+ uses_user_vertex_buffers = true;
if (!binding->InstanceDivisor)
st->draw_needs_minmax_index = true;
}
input_to_index[attr]);
}
}
+ *has_user_vertex_buffers = uses_user_vertex_buffers;
}
void
unsigned num_vbuffers = 0, first_upload_vbuffer;
struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
unsigned num_velements;
+ bool uses_user_vertex_buffers;
st->draw_needs_minmax_index = false;
/* ST_NEW_VERTEX_ARRAYS alias ctx->DriverFlags.NewArray */
/* Setup arrays */
- st_setup_arrays(st, vp, vp_variant, velements, vbuffer, &num_vbuffers);
+ st_setup_arrays(st, vp, vp_variant, velements, vbuffer, &num_vbuffers,
+ &uses_user_vertex_buffers);
/* _NEW_CURRENT_ATTRIB */
/* Setup current uploads */
/* Set the array into cso */
num_velements = vp->num_inputs + vp_variant->key.passthrough_edgeflags;
- set_vertex_attribs(st, vbuffer, num_vbuffers, velements, num_velements);
+
+ /* Set vertex buffers and elements. */
+ struct cso_context *cso = st->cso_context;
+ unsigned unbind_trailing_vbuffers =
+ st->last_num_vbuffers > num_vbuffers ?
+ st->last_num_vbuffers - num_vbuffers : 0;
+ cso_set_vertex_buffers_and_elements(cso, num_velements, velements,
+ num_vbuffers,
+ unbind_trailing_vbuffers,
+ vbuffer, uses_user_vertex_buffers);
+ st->last_num_vbuffers = num_vbuffers;
/* Unreference uploaded buffer resources. */
for (unsigned i = first_upload_vbuffer; i < num_vbuffers; ++i) {
/* Must setup these after state validation! */
/* Setup arrays */
- st_setup_arrays(st, vp, vp_variant, velements, vbuffers, &num_vbuffers);
+ bool uses_user_vertex_buffers;
+ st_setup_arrays(st, vp, vp_variant, velements, vbuffers, &num_vbuffers,
+ &uses_user_vertex_buffers);
/* Setup current values as userspace arrays */
st_setup_current_user(st, vp, vp_variant, velements, vbuffers, &num_vbuffers);