}
+void
+_mesa_update_primitive_id_is_unused(struct gl_context *ctx)
+{
+ /* Only the compatibility profile with display lists needs this. */
+ if (ctx->API != API_OPENGL_COMPAT)
+ return;
+
+ /* If all of these are NULL, GLSL is disabled. */
+ struct gl_program *tcs =
+ ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_CTRL];
+ struct gl_program *tes =
+ ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
+ struct gl_program *gs =
+ ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
+ struct gl_program *fs =
+ ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT];
+
+ /* Update ctx->_PrimitiveIDIsUnused for display list if
+ * allow_incorrect_primitive_id isn't enabled.
+ * We can use merged primitives (see vbo_save) for drawing unless
+ * one program expects a correct primitive-ID value.
+ */
+ /* TODO: it may be possible to relax the restriction in some cases. If the current
+ * geometry shader doesn't read gl_PrimitiveIDIn but does write gl_PrimitiveID,
+ * then the restriction on fragment shaders reading gl_PrimitiveID can be lifted.
+ */
+ ctx->_PrimitiveIDIsUnused = !(
+ (tcs && (tcs->info.system_values_read & BITFIELD64_BIT(SYSTEM_VALUE_PRIMITIVE_ID) ||
+ tcs->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)) ||
+ (tes && (tes->info.system_values_read & BITFIELD64_BIT(SYSTEM_VALUE_PRIMITIVE_ID) ||
+ tes->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)) ||
+ (gs && (gs->info.system_values_read & BITFIELD64_BIT(SYSTEM_VALUE_PRIMITIVE_ID) ||
+ gs->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)) ||
+ (fs && (fs->info.system_values_read & BITFIELD64_BIT(SYSTEM_VALUE_PRIMITIVE_ID) ||
+ fs->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)));
+}
+
+
/**
* Update the ctx->*Program._Current pointers to point to the
* current/active programs.
node->vertex_count = save->vert_count;
node->wrap_count = save->copied.nr;
node->prims = save->prims;
+ node->merged.prims = NULL;
+ node->merged.ib.obj = NULL;
+ node->merged.prim_count = 0;
node->prim_count = save->prim_count;
node->prim_store = save->prim_store;
/* Create an index buffer. */
node->min_index = node->max_index = 0;
if (save->vert_count) {
- int end = node->prims[node->prim_count - 1].start +
- node->prims[node->prim_count - 1].count;
- int total_vert_count = end - node->prims[0].start;
+ /* 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,
int last_valid_prim = -1;
/* Construct indices array. */
for (unsigned i = 0; i < node->prim_count; i++) {
- assert(node->prims[i].basevertex == 0);
- GLubyte mode = node->prims[i].mode;
+ assert(original_prims[i].basevertex == 0);
+ GLubyte mode = original_prims[i].mode;
- int vertex_count = node->prims[i].count;
+ int vertex_count = original_prims[i].count;
if (!vertex_count) {
continue;
}
/* If 2 consecutive prims use the same mode => merge them. */
bool merge_prims = last_valid_prim >= 0 &&
- mode == node->prims[last_valid_prim].mode &&
+ mode == node->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 (merge_prims &&
mode == GL_TRIANGLE_STRIP) {
/* Insert a degenerate triangle */
- assert(node->prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
- unsigned tri_count = node->prims[last_valid_prim].count - 2;
+ assert(node->merged.prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
+ unsigned tri_count = node->merged.prims[last_valid_prim].count - 2;
indices[idx] = indices[idx - 1];
- indices[idx + 1] = node->prims[i].start;
+ indices[idx + 1] = original_prims[i].start;
idx += 2;
- node->prims[last_valid_prim].count += 2;
+ node->merged.prims[last_valid_prim].count += 2;
if (tri_count % 2) {
/* Add another index to preserve winding order */
- indices[idx++] = node->prims[i].start;
- node->prims[last_valid_prim].count++;
+ indices[idx++] = original_prims[i].start;
+ node->merged.prims[last_valid_prim].count++;
}
}
* prim mode is GL_LINES (so merge_prims is true) or if the next
* primitive mode is GL_LINES or GL_LINE_LOOP.
*/
- if (node->prims[i].mode == GL_LINE_STRIP &&
+ if (original_prims[i].mode == GL_LINE_STRIP &&
(merge_prims ||
(i < node->prim_count - 1 &&
- (node->prims[i + 1].mode == GL_LINE_STRIP ||
- node->prims[i + 1].mode == GL_LINES)))) {
+ (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++] = node->prims[i].start + j;
+ indices[idx++] = original_prims[i].start + j;
/* Repeat all but the first/last indices. */
if (j && j != vertex_count - 1) {
- indices[idx++] = node->prims[i].start + j;
- node->prims[i].count++;
+ indices[idx++] = original_prims[i].start + j;
}
}
- node->prims[i].mode = mode;
} else {
for (unsigned j = 0; j < vertex_count; j++) {
- indices[idx++] = node->prims[i].start + j;
+ indices[idx++] = original_prims[i].start + j;
}
}
if (merge_prims) {
/* Update vertex count. */
- node->prims[last_valid_prim].count += idx - start;
+ node->merged.prims[last_valid_prim].count += idx - start;
} else {
/* Keep this primitive */
last_valid_prim += 1;
assert(last_valid_prim <= i);
- node->prims[i].start = start;
- node->prims[last_valid_prim] = node->prims[i];
+ node->merged.prims = realloc(node->merged.prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
+ node->merged.prims[last_valid_prim] = original_prims[i];
+ node->merged.prims[last_valid_prim].start = start;
+ node->merged.prims[last_valid_prim].count = idx - start;
}
+ node->merged.prims[last_valid_prim].mode = mode;
}
if (idx == 0)
assert(idx <= max_indices_count);
- node->prim_count = last_valid_prim + 1;
- node->ib.ptr = NULL;
- node->ib.count = idx;
- node->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
- node->min_index = min_index;
- node->max_index = max_index;
+ node->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;
+ node->merged.min_index = min_index;
+ node->merged.max_index = max_index;
- node->ib.obj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
+ node->merged.ib.obj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
bool success = ctx->Driver.BufferData(ctx,
GL_ELEMENT_ARRAY_BUFFER_ARB,
idx * sizeof(uint32_t), indices,
GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
- node->ib.obj);
+ node->merged.ib.obj);
if (success)
goto out;
- ctx->Driver.DeleteBuffer(ctx, node->ib.obj);
+ ctx->Driver.DeleteBuffer(ctx, node->merged.ib.obj);
_mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
skip_node:
- node->ib.obj = NULL;
+ node->merged.ib.obj = NULL;
node->vertex_count = 0;
node->prim_count = 0;
out:
free(indices);
- } else {
- node->ib.obj = NULL;
}
/* Deal with GL_COMPILE_AND_EXECUTE:
free(node->prim_store);
}
- _mesa_reference_buffer_object(ctx, &node->ib.obj, NULL);
+ free(node->merged.prims);
+
+ _mesa_reference_buffer_object(ctx, &node->merged.ib.obj, NULL);
free(node->current_data);
node->current_data = NULL;
}