/* Create an index buffer. */
node->min_index = node->max_index = 0;
- if (save->vert_count && node->prim_count) {
- /* We won't modify node->prims, so use a const alias to avoid unintended
- * writes to it. */
- const struct _mesa_prim *original_prims = node->prims;
-
- int end = original_prims[node->prim_count - 1].start +
- original_prims[node->prim_count - 1].count;
- int total_vert_count = end - original_prims[0].start;
-
- node->min_index = node->prims[0].start;
- node->max_index = end - 1;
-
- /* Estimate for the worst case: all prims are line strips (the +1 is because
- * wrap_buffers may call use but the last primitive may not be complete) */
- int max_indices_count = MAX2(total_vert_count * 2 - (node->prim_count * 2) + 1,
- total_vert_count);
-
- int indices_offset = 0;
- int available = save->previous_ib ? (save->previous_ib->Size / 4 - save->ib_first_free_index) : 0;
- if (available >= max_indices_count) {
- indices_offset = save->ib_first_free_index;
- }
- int size = max_indices_count * sizeof(uint32_t);
- uint32_t* indices = (uint32_t*) malloc(size);
- struct _mesa_prim *merged_prims = NULL;
-
- int idx = 0;
+ if (save->vert_count == 0 || save->prim_count == 0)
+ goto end;
- int last_valid_prim = -1;
- /* Construct indices array. */
- for (unsigned i = 0; i < node->prim_count; i++) {
- assert(original_prims[i].basevertex == 0);
- GLubyte mode = original_prims[i].mode;
+ /* We won't modify node->prims, so use a const alias to avoid unintended
+ * writes to it. */
+ const struct _mesa_prim *original_prims = node->prims;
- int vertex_count = original_prims[i].count;
- if (!vertex_count) {
- continue;
- }
+ int end = original_prims[node->prim_count - 1].start +
+ original_prims[node->prim_count - 1].count;
+ int total_vert_count = end - original_prims[0].start;
- /* Line strips may get converted to lines */
- if (mode == GL_LINE_STRIP)
- mode = GL_LINES;
+ node->min_index = node->prims[0].start;
+ node->max_index = end - 1;
- /* If 2 consecutive prims use the same mode => merge them. */
- bool merge_prims = last_valid_prim >= 0 &&
- mode == merged_prims[last_valid_prim].mode &&
- mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
- mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
- mode != GL_PATCHES;
+ /* Estimate for the worst case: all prims are line strips (the +1 is because
+ * wrap_buffers may call use but the last primitive may not be complete) */
+ int max_indices_count = MAX2(total_vert_count * 2 - (node->prim_count * 2) + 1,
+ total_vert_count);
- /* To be able to merge consecutive triangle strips we need to insert
- * a degenerate triangle.
- */
- if (merge_prims &&
- mode == GL_TRIANGLE_STRIP) {
- /* Insert a degenerate triangle */
- assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
- unsigned tri_count = merged_prims[last_valid_prim].count - 2;
-
- indices[idx] = indices[idx - 1];
- indices[idx + 1] = original_prims[i].start;
- idx += 2;
- merged_prims[last_valid_prim].count += 2;
-
- if (tri_count % 2) {
- /* Add another index to preserve winding order */
- indices[idx++] = original_prims[i].start;
- merged_prims[last_valid_prim].count++;
- }
- }
-
- int start = idx;
+ int indices_offset = 0;
+ int available = save->previous_ib ? (save->previous_ib->Size / 4 - save->ib_first_free_index) : 0;
+ if (available >= max_indices_count) {
+ indices_offset = save->ib_first_free_index;
+ }
+ int size = max_indices_count * sizeof(uint32_t);
+ uint32_t* indices = (uint32_t*) malloc(size);
+ struct _mesa_prim *merged_prims = NULL;
- /* Convert line strips to lines if it'll allow if the previous
- * prim mode is GL_LINES (so merge_prims is true) or if the next
- * primitive mode is GL_LINES or GL_LINE_LOOP.
- */
- if (original_prims[i].mode == GL_LINE_STRIP &&
- (merge_prims ||
- (i < node->prim_count - 1 &&
- (original_prims[i + 1].mode == GL_LINE_STRIP ||
- original_prims[i + 1].mode == GL_LINES)))) {
- for (unsigned j = 0; j < vertex_count; j++) {
- indices[idx++] = original_prims[i].start + j;
- /* Repeat all but the first/last indices. */
- if (j && j != vertex_count - 1) {
- indices[idx++] = original_prims[i].start + j;
- }
- }
- } else {
- /* We didn't convert to LINES, so restore the original mode */
- mode = original_prims[i].mode;
+ int idx = 0;
- for (unsigned j = 0; j < vertex_count; j++) {
- indices[idx++] = original_prims[i].start + j;
- }
- }
+ int last_valid_prim = -1;
+ /* Construct indices array. */
+ for (unsigned i = 0; i < node->prim_count; i++) {
+ assert(original_prims[i].basevertex == 0);
+ GLubyte mode = original_prims[i].mode;
- if (merge_prims) {
- /* Update vertex count. */
- merged_prims[last_valid_prim].count += idx - start;
- } else {
- /* Keep this primitive */
- last_valid_prim += 1;
- assert(last_valid_prim <= i);
- merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
- merged_prims[last_valid_prim] = original_prims[i];
- merged_prims[last_valid_prim].start = indices_offset + start;
- merged_prims[last_valid_prim].count = idx - start;
- }
- merged_prims[last_valid_prim].mode = mode;
+ int vertex_count = original_prims[i].count;
+ if (!vertex_count) {
+ continue;
}
- assert(idx > 0 && idx <= max_indices_count);
+ /* Line strips may get converted to lines */
+ if (mode == GL_LINE_STRIP)
+ mode = GL_LINES;
- unsigned merged_prim_count = last_valid_prim + 1;
- node->merged.ib.ptr = NULL;
- node->merged.ib.count = idx;
- node->merged.ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
+ /* If 2 consecutive prims use the same mode => merge them. */
+ bool merge_prims = last_valid_prim >= 0 &&
+ mode == merged_prims[last_valid_prim].mode &&
+ mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
+ mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
+ mode != GL_PATCHES;
- if (!indices_offset) {
- /* Allocate a new index buffer */
- _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
- save->previous_ib = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
- bool success = ctx->Driver.BufferData(ctx,
- GL_ELEMENT_ARRAY_BUFFER_ARB,
- MAX2(VBO_SAVE_INDEX_SIZE, idx) * sizeof(uint32_t),
- NULL,
- GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
- save->previous_ib);
- if (!success) {
- _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
+ /* To be able to merge consecutive triangle strips we need to insert
+ * a degenerate triangle.
+ */
+ if (merge_prims &&
+ mode == GL_TRIANGLE_STRIP) {
+ /* Insert a degenerate triangle */
+ assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
+ unsigned tri_count = merged_prims[last_valid_prim].count - 2;
+
+ indices[idx] = indices[idx - 1];
+ indices[idx + 1] = original_prims[i].start;
+ idx += 2;
+ merged_prims[last_valid_prim].count += 2;
+
+ if (tri_count % 2) {
+ /* Add another index to preserve winding order */
+ indices[idx++] = original_prims[i].start;
+ merged_prims[last_valid_prim].count++;
}
}
- _mesa_reference_buffer_object(ctx, &node->merged.ib.obj, save->previous_ib);
+ int start = idx;
- if (node->merged.ib.obj) {
- ctx->Driver.BufferSubData(ctx,
- indices_offset * sizeof(uint32_t),
- idx * sizeof(uint32_t),
- indices,
- node->merged.ib.obj);
- save->ib_first_free_index = indices_offset + idx;
+ /* Convert line strips to lines if it'll allow if the previous
+ * prim mode is GL_LINES (so merge_prims is true) or if the next
+ * primitive mode is GL_LINES or GL_LINE_LOOP.
+ */
+ if (original_prims[i].mode == GL_LINE_STRIP &&
+ (merge_prims ||
+ (i < node->prim_count - 1 &&
+ (original_prims[i + 1].mode == GL_LINE_STRIP ||
+ original_prims[i + 1].mode == GL_LINES)))) {
+ for (unsigned j = 0; j < vertex_count; j++) {
+ indices[idx++] = original_prims[i].start + j;
+ /* Repeat all but the first/last indices. */
+ if (j && j != vertex_count - 1) {
+ indices[idx++] = original_prims[i].start + j;
+ }
+ }
} else {
- node->vertex_count = 0;
- node->prim_count = 0;
+ /* We didn't convert to LINES, so restore the original mode */
+ mode = original_prims[i].mode;
+
+ for (unsigned j = 0; j < vertex_count; j++) {
+ indices[idx++] = original_prims[i].start + j;
+ }
}
- /* Prepare for DrawGallium */
- memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
- /* The other info fields will be updated in vbo_save_playback_vertex_list */
- node->merged.info.index_size = 4;
- node->merged.info.instance_count = 1;
- node->merged.info.index.gl_bo = node->merged.ib.obj;
- node->merged.start_count = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
- if (merged_prim_count == 1) {
- node->merged.info.mode = merged_prims[0].mode;
- node->merged.mode = NULL;
+ if (merge_prims) {
+ /* Update vertex count. */
+ merged_prims[last_valid_prim].count += idx - start;
} else {
- node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
+ /* Keep this primitive */
+ last_valid_prim += 1;
+ assert(last_valid_prim <= i);
+ merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
+ merged_prims[last_valid_prim] = original_prims[i];
+ merged_prims[last_valid_prim].start = indices_offset + start;
+ merged_prims[last_valid_prim].count = idx - start;
+ }
+ merged_prims[last_valid_prim].mode = mode;
+ }
+
+ assert(idx > 0 && idx <= max_indices_count);
+
+ unsigned merged_prim_count = last_valid_prim + 1;
+ node->merged.ib.ptr = NULL;
+ node->merged.ib.count = idx;
+ node->merged.ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
+
+ if (!indices_offset) {
+ /* Allocate a new index buffer */
+ _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
+ save->previous_ib = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
+ bool success = ctx->Driver.BufferData(ctx,
+ GL_ELEMENT_ARRAY_BUFFER_ARB,
+ MAX2(VBO_SAVE_INDEX_SIZE, idx) * sizeof(uint32_t),
+ NULL,
+ GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
+ save->previous_ib);
+ if (!success) {
+ _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
}
+ }
+
+ _mesa_reference_buffer_object(ctx, &node->merged.ib.obj, save->previous_ib);
- for (unsigned i = 0; i < merged_prim_count; i++) {
- node->merged.start_count[i].start = merged_prims[i].start;
- node->merged.start_count[i].count = merged_prims[i].count;
- node->merged.start_count[i].index_bias = 0;
- if (merged_prim_count > 1)
- node->merged.mode[i] = merged_prims[i].mode;
+ if (node->merged.ib.obj) {
+ ctx->Driver.BufferSubData(ctx,
+ indices_offset * sizeof(uint32_t),
+ idx * sizeof(uint32_t),
+ indices,
+ node->merged.ib.obj);
+ save->ib_first_free_index = indices_offset + idx;
+ } else {
+ node->vertex_count = 0;
+ node->prim_count = 0;
+ }
+
+ /* Prepare for DrawGallium */
+ memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
+ /* The other info fields will be updated in vbo_save_playback_vertex_list */
+ node->merged.info.index_size = 4;
+ node->merged.info.instance_count = 1;
+ node->merged.info.index.gl_bo = node->merged.ib.obj;
+ node->merged.start_count = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
+ if (merged_prim_count == 1) {
+ node->merged.info.mode = merged_prims[0].mode;
+ node->merged.mode = NULL;
+ } else {
+ node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
+ }
+
+ for (unsigned i = 0; i < merged_prim_count; i++) {
+ node->merged.start_count[i].start = merged_prims[i].start;
+ node->merged.start_count[i].count = merged_prims[i].count;
+ node->merged.start_count[i].index_bias = 0;
+ if (merged_prim_count > 1)
+ node->merged.mode[i] = merged_prims[i].mode;
+ }
+ node->merged.num_draws = merged_prim_count;
+ if (node->merged.num_draws > 1) {
+ bool same_mode = true;
+ for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
+ same_mode = node->merged.mode[i] == node->merged.mode[0];
}
- node->merged.num_draws = merged_prim_count;
- if (node->merged.num_draws > 1) {
- bool same_mode = true;
- for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
- same_mode = node->merged.mode[i] == node->merged.mode[0];
- }
- if (same_mode) {
- /* All primitives use the same mode, so we can simplify a bit */
- node->merged.info.mode = node->merged.mode[0];
- free(node->merged.mode);
- node->merged.mode = NULL;
- }
+ if (same_mode) {
+ /* All primitives use the same mode, so we can simplify a bit */
+ node->merged.info.mode = node->merged.mode[0];
+ free(node->merged.mode);
+ node->merged.mode = NULL;
}
-
- free(indices);
- free(merged_prims);
}
+ free(indices);
+ free(merged_prims);
+
+end:
/* Deal with GL_COMPILE_AND_EXECUTE:
*/
if (ctx->ExecuteFlag) {
FLUSH_FOR_DRAW(ctx);
- if (node->prim_count > 0) {
-
- if (_mesa_inside_begin_end(ctx) && node->prims[0].begin) {
- /* Error: we're about to begin a new primitive but we're already
- * inside a glBegin/End pair.
- */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "draw operation inside glBegin/End");
- goto end;
- }
- else if (save->replay_flags) {
- /* Various degenerate cases: translate into immediate mode
- * calls rather than trying to execute in place.
- */
- loopback_vertex_list(ctx, node);
+ if (_mesa_inside_begin_end(ctx) && node->prims[0].begin) {
+ /* Error: we're about to begin a new primitive but we're already
+ * inside a glBegin/End pair.
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "draw operation inside glBegin/End");
+ goto end;
+ }
+ else if (save->replay_flags) {
+ /* Various degenerate cases: translate into immediate mode
+ * calls rather than trying to execute in place.
+ */
+ loopback_vertex_list(ctx, node);
- goto end;
- }
+ goto end;
+ }
- bind_vertex_list(ctx, node);
+ bind_vertex_list(ctx, node);
- /* Need that at least one time. */
- if (ctx->NewState)
- _mesa_update_state(ctx);
+ /* Need that at least one time. */
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
- /* XXX also need to check if shader enabled, but invalid */
- if ((ctx->VertexProgram.Enabled &&
- !_mesa_arb_vertex_program_enabled(ctx)) ||
- (ctx->FragmentProgram.Enabled &&
- !_mesa_arb_fragment_program_enabled(ctx))) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBegin (invalid vertex/fragment program)");
- return;
- }
+ /* XXX also need to check if shader enabled, but invalid */
+ if ((ctx->VertexProgram.Enabled &&
+ !_mesa_arb_vertex_program_enabled(ctx)) ||
+ (ctx->FragmentProgram.Enabled &&
+ !_mesa_arb_fragment_program_enabled(ctx))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBegin (invalid vertex/fragment program)");
+ return;
+ }
- assert(ctx->NewState == 0);
-
- if (node->vertex_count > 0) {
- bool draw_using_merged_prim = (ctx->Const.AllowIncorrectPrimitiveId ||
- ctx->_PrimitiveIDIsUnused) &&
- node->merged.num_draws;
- if (!draw_using_merged_prim) {
- ctx->Driver.Draw(ctx, node->prims, node->prim_count,
- NULL, true,
- false, 0, node->min_index, node->max_index, 1, 0);
- } else {
- struct pipe_draw_info *info = (struct pipe_draw_info *) &node->merged.info;
- info->vertices_per_patch = ctx->TessCtrlProgram.patch_vertices;
- void *gl_bo = info->index.gl_bo;
- if (node->merged.mode) {
- ctx->Driver.DrawGalliumMultiMode(ctx, info, 0,
- node->merged.start_count,
- node->merged.mode,
- node->merged.num_draws);
- } else {
- ctx->Driver.DrawGallium(ctx, info, 0,
- node->merged.start_count,
- node->merged.num_draws);
- }
- info->index.gl_bo = gl_bo;
- }
+ assert(ctx->NewState == 0);
+
+ bool draw_using_merged_prim = (ctx->Const.AllowIncorrectPrimitiveId ||
+ ctx->_PrimitiveIDIsUnused) &&
+ node->merged.num_draws;
+ if (!draw_using_merged_prim) {
+ ctx->Driver.Draw(ctx, node->prims, node->prim_count,
+ NULL, true,
+ false, 0, node->min_index, node->max_index, 1, 0);
+ } else {
+ struct pipe_draw_info *info = (struct pipe_draw_info *) &node->merged.info;
+ info->vertices_per_patch = ctx->TessCtrlProgram.patch_vertices;
+ void *gl_bo = info->index.gl_bo;
+ if (node->merged.mode) {
+ ctx->Driver.DrawGalliumMultiMode(ctx, info, 0,
+ node->merged.start_count,
+ node->merged.mode,
+ node->merged.num_draws);
+ } else if (node->merged.num_draws) {
+ ctx->Driver.DrawGallium(ctx, info, 0,
+ node->merged.start_count,
+ node->merged.num_draws);
}
+ info->index.gl_bo = gl_bo;
}
/* Copy to current?