OPCODE_NAMED_PROGRAM_LOCAL_PARAMETER,
OPCODE_VERTEX_LIST,
+ OPCODE_VERTEX_LIST_LOOPBACK,
/* The following three are meta instructions */
OPCODE_ERROR, /* raise compiled-in error */
}
static void
-vbo_print_vertex_list(struct gl_context *ctx, struct vbo_save_vertex_list *node, FILE *f)
+vbo_print_vertex_list(struct gl_context *ctx, struct vbo_save_vertex_list *node, OpCode op, FILE *f)
{
GLuint i;
struct gl_buffer_object *buffer = node->VAO[0]->BufferBinding[0].BufferObj;
const GLuint vertex_size = _vbo_save_get_stride(node)/sizeof(GLfloat);
(void) ctx;
- fprintf(f, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
+ const char *label[] = {
+ "VBO-VERTEX-LIST", "VBO-VERTEX-LIST-LOOPBACK"
+ };
+
+ fprintf(f, "%s, %u vertices, %d primitives, %d vertsize, "
"buffer %p\n",
+ label[op - OPCODE_VERTEX_LIST],
node->cold->vertex_count, node->cold->prim_count, vertex_size,
buffer);
free(get_pointer(&n[5]));
break;
case OPCODE_VERTEX_LIST:
+ case OPCODE_VERTEX_LIST_LOOPBACK:
vbo_destroy_vertex_list(ctx, (struct vbo_save_vertex_list *) &n[1]);
break;
case OPCODE_CONTINUE:
for (i = 0; i < MAT_ATTRIB_MAX; i++)
ctx->ListState.ActiveMaterialSize[i] = 0;
+ /* Loopback usage applies recursively, so remember this state */
+ bool use_loopback = ctx->ListState.Current.UseLoopback;
memset(&ctx->ListState.Current, 0, sizeof ctx->ListState.Current);
+ ctx->ListState.Current.UseLoopback = use_loopback;
ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
}
ctx->ListState.CallDepth++;
- vbo_save_BeginCallList(ctx, dlist);
-
n = dlist->Head;
while (1) {
vbo_save_playback_vertex_list(ctx, &n[1]);
break;
+ case OPCODE_VERTEX_LIST_LOOPBACK:
+ vbo_save_playback_vertex_list_loopback(ctx, &n[1]);
+ break;
+
case OPCODE_CONTINUE:
n = (Node *) get_pointer(&n[1]);
continue;
}
FALLTHROUGH;
case OPCODE_END_OF_LIST:
- vbo_save_EndCallList(ctx);
ctx->ListState.CallDepth--;
return;
}
ctx->ListState.CurrentList = make_list(name, BLOCK_SIZE);
ctx->ListState.CurrentBlock = ctx->ListState.CurrentList->Head;
ctx->ListState.CurrentPos = 0;
+ ctx->ListState.Current.UseLoopback = false;
vbo_save_NewList(ctx, name, mode);
/**
+ * Walk all the opcode from a given list, recursively if OPCODE_CALL_LIST(S) is used,
+ * and replace OPCODE_VERTEX_LIST[_COPY_CURRENT] occurences by OPCODE_VERTEX_LIST_LOOPBACK.
+ */
+static void
+replace_op_vertex_list_recursively(struct gl_context *ctx, struct gl_display_list *dlist)
+{
+ Node *n = dlist->Head;
+ while (true) {
+ const OpCode opcode = n[0].opcode;
+ switch (opcode) {
+ case OPCODE_VERTEX_LIST:
+ n[0].opcode = OPCODE_VERTEX_LIST_LOOPBACK;
+ break;
+ case OPCODE_CONTINUE:
+ n = (Node *)get_pointer(&n[1]);
+ continue;
+ case OPCODE_CALL_LIST:
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)n[1].ui, true));
+ break;
+ case OPCODE_CALL_LISTS: {
+ GLbyte *bptr;
+ GLubyte *ubptr;
+ GLshort *sptr;
+ GLushort *usptr;
+ GLint *iptr;
+ GLuint *uiptr;
+ GLfloat *fptr;
+ switch(n[2].e) {
+ case GL_BYTE:
+ bptr = (GLbyte *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++)
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)bptr[i], true));
+ break;
+ case GL_UNSIGNED_BYTE:
+ ubptr = (GLubyte *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++)
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)ubptr[i], true));
+ break;
+ case GL_SHORT:
+ sptr = (GLshort *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++)
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)sptr[i], true));
+ break;
+ case GL_UNSIGNED_SHORT:
+ usptr = (GLushort *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++)
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)usptr[i], true));
+ break;
+ case GL_INT:
+ iptr = (GLint *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++)
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)iptr[i], true));
+ break;
+ case GL_UNSIGNED_INT:
+ uiptr = (GLuint *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++)
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)uiptr[i], true));
+ break;
+ case GL_FLOAT:
+ fptr = (GLfloat *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++)
+ replace_op_vertex_list_recursively(ctx, _mesa_lookup_list(ctx, (int)fptr[i], true));
+ break;
+ case GL_2_BYTES:
+ ubptr = (GLubyte *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++) {
+ replace_op_vertex_list_recursively(ctx,
+ _mesa_lookup_list(ctx, (int)ubptr[2 * i] * 256 +
+ (int)ubptr[2 * i + 1], true));
+ }
+ break;
+ case GL_3_BYTES:
+ ubptr = (GLubyte *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++) {
+ replace_op_vertex_list_recursively(ctx,
+ _mesa_lookup_list(ctx, (int)ubptr[3 * i] * 65536 +
+ (int)ubptr[3 * i + 1] * 256 +
+ (int)ubptr[3 * i + 2], true));
+ }
+ break;
+ case GL_4_BYTES:
+ ubptr = (GLubyte *) get_pointer(&n[3]);
+ for (unsigned i = 0; i < n[1].i; i++) {
+ replace_op_vertex_list_recursively(ctx,
+ _mesa_lookup_list(ctx, (int)ubptr[4 * i] * 16777216 +
+ (int)ubptr[4 * i + 1] * 65536 +
+ (int)ubptr[4 * i + 2] * 256 +
+ (int)ubptr[4 * i + 3], true));
+ }
+ break;
+ }
+ break;
+ }
+ case OPCODE_END_OF_LIST:
+ return;
+ default:
+ break;
+ }
+ n += n[0].InstSize;
+ }
+}
+
+
+/**
* End definition of current display list.
*/
void GLAPIENTRY
(void) alloc_instruction(ctx, OPCODE_END_OF_LIST, 0);
+ if (ctx->ListState.Current.UseLoopback) {
+ _mesa_HashLockMutex(ctx->Shared->DisplayList);
+ replace_op_vertex_list_recursively(ctx, ctx->ListState.CurrentList);
+ _mesa_HashUnlockMutex(ctx->Shared->DisplayList);
+ }
+
trim_list(ctx);
/* Destroy old list, if any */
fprintf(f, "NOP\n");
break;
case OPCODE_VERTEX_LIST:
- vbo_print_vertex_list(ctx, (struct vbo_save_vertex_list *) &n[1], f);
+ case OPCODE_VERTEX_LIST_LOOPBACK:
+ vbo_print_vertex_list(ctx, (struct vbo_save_vertex_list *) &n[1], opcode, f);
break;
default:
if (opcode < 0 || opcode > OPCODE_END_OF_LIST) {
}
-/**
- * Execute the buffer and save copied verts.
- * This is called from the display list code when executing
- * a drawing command.
- */
void
-vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
+vbo_save_playback_vertex_list_loopback(struct gl_context *ctx, void *data)
{
const struct vbo_save_vertex_list *node =
(const struct vbo_save_vertex_list *) data;
"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);
+ /* Various degenerate cases: translate into immediate mode
+ * calls rather than trying to execute in place.
+ */
+ loopback_vertex_list(ctx, node);
- goto end;
+end:
+ if (remap_vertex_store) {
+ save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
+ }
+}
+
+/**
+ * Execute the buffer and save copied verts.
+ * This is called from the display list code when executing
+ * a drawing command.
+ */
+void
+vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
+{
+ const struct vbo_save_vertex_list *node =
+ (const struct vbo_save_vertex_list *) data;
+
+ FLUSH_FOR_DRAW(ctx);
+
+ if (_mesa_inside_begin_end(ctx) && node->cold->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");
+ return;
}
bind_vertex_list(ctx, node);
/* Copy to current?
*/
playback_copy_to_current(ctx, node);
-
-end:
- if (remap_vertex_store) {
- save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
- }
}