+ struct pipe_vertex_buffer *vb, *vbufs = r300->vertex_buffer;
+ struct pipe_vertex_element *velem = r300->velems->velem;
+ unsigned i, size;
+ int max_neg_bias;
+
+ if (index_bias < 0) {
+ /* See how large index bias we may subtract. We must be careful
+ * here because negative buffer offsets are not allowed
+ * by the DRM API. */
+ max_neg_bias = INT_MAX;
+ for (i = 0; i < r300->velems->count; i++) {
+ vb = &vbufs[velem[i].vertex_buffer_index];
+ size = (vb->buffer_offset + velem[i].src_offset) / vb->stride;
+ max_neg_bias = MIN2(max_neg_bias, size);
+ }
+
+ /* Now set the minimum allowed value. */
+ *buffer_offset = MAX2(-max_neg_bias, index_bias);
+ } else {
+ /* A positive index bias is OK. */
+ *buffer_offset = index_bias;
+ }
+
+ *index_offset = index_bias - *buffer_offset;
+}
+
+enum r300_prepare_flags {
+ PREP_FIRST_DRAW = (1 << 0), /* call emit_dirty_state and friends? */
+ PREP_VALIDATE_VBOS = (1 << 1), /* validate VBOs? */
+ PREP_EMIT_AOS = (1 << 2), /* call emit_aos? */
+ PREP_EMIT_AOS_SWTCL = (1 << 3), /* call emit_aos_swtcl? */
+ PREP_INDEXED = (1 << 4) /* is this draw_elements? */
+};
+
+/**
+ * Check if the requested number of dwords is available in the CS and
+ * if not, flush. Then validate buffers and emit dirty state.
+ * \param r300 The context.
+ * \param flags See r300_prepare_flags.
+ * \param index_buffer The index buffer to validate. The parameter may be NULL.
+ * \param cs_dwords The number of dwords to reserve in CS.
+ * \param aos_offset The offset passed to emit_aos.
+ * \param index_bias The index bias to emit.
+ * \param end_cs_dwords The number of free dwords which must be available
+ * at the end of CS after drawing in case the CS space
+ * management is performed by a draw_* function manually.
+ * The parameter may be NULL.
+ */
+static void r300_prepare_for_rendering(struct r300_context *r300,
+ enum r300_prepare_flags flags,
+ struct pipe_resource *index_buffer,
+ unsigned cs_dwords,
+ int aos_offset,
+ int index_bias,
+ unsigned *end_cs_dwords)
+{
+ unsigned end_dwords = 0;
+ boolean flushed = FALSE;
+ boolean first_draw = flags & PREP_FIRST_DRAW;
+ boolean emit_aos = flags & PREP_EMIT_AOS;
+ boolean emit_aos_swtcl = flags & PREP_EMIT_AOS_SWTCL;
+ boolean indexed = flags & PREP_INDEXED;
+ boolean hw_index_bias = index_bias_supported(r300);
+
+ /* Add dirty state, index offset, and AOS. */
+ if (first_draw) {
+ cs_dwords += r300_get_num_dirty_dwords(r300);
+
+ if (hw_index_bias)
+ cs_dwords += 2; /* emit_index_offset */
+
+ if (emit_aos)
+ cs_dwords += 55; /* emit_aos */
+
+ if (emit_aos_swtcl)
+ cs_dwords += 7; /* emit_aos_swtcl */
+ }
+
+ /* Emitted in flush. */
+ end_dwords += 26; /* emit_query_end */
+
+ cs_dwords += end_dwords;
+
+ /* Reserve requested CS space. */
+ if (!r300_check_cs(r300, cs_dwords)) {