summaryrefslogtreecommitdiffstats
path: root/src/mesa
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2013-01-16 15:20:45 -0800
committerEric Anholt <[email protected]>2013-01-21 21:26:47 -0800
commitc572251417ef20d1d560b849931321a42b1be578 (patch)
treeeda6535447a1b48532e286c8dc1a74dba935858d /src/mesa
parent0aaf0445bac453db474cedf27f1d9f45e4acde4d (diff)
mesa: Install a minimal dispatch table during glBegin()/glEnd().
This is a step toward getting rid of ASSERT_OUTSIDE_BEGIN_END() in Mesa. v2: Finish create_beginend_table() comment, move loopback API init into it, and add a const flag. (suggestions by Brian) Reviewed-by: Brian Paul <[email protected]> (v1) Reviewed-by: Ian Romanick <[email protected]> (v1)
Diffstat (limited to 'src/mesa')
-rw-r--r--src/mesa/main/context.c108
-rw-r--r--src/mesa/main/mtypes.h25
-rw-r--r--src/mesa/main/vtxfmt.c2
-rw-r--r--src/mesa/vbo/vbo_exec_api.c17
4 files changed, 133 insertions, 19 deletions
diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 561eb4685e3..e30b63a443e 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -81,6 +81,7 @@
#include "imports.h"
#include "accum.h"
#include "api_exec.h"
+#include "api_loopback.h"
#include "arrayobj.h"
#include "attrib.h"
#include "blend.h"
@@ -859,6 +860,81 @@ _mesa_alloc_dispatch_table(int size)
return table;
}
+/**
+ * Creates a minimal dispatch table for use within glBegin()/glEnd().
+ *
+ * This ensures that we generate GL_INVALID_OPERATION errors from most
+ * functions, since the set of functions that are valid within Begin/End is
+ * very small.
+ *
+ * From the GL 1.0 specification section 2.6.3, "GL Commands within
+ * Begin/End"
+ *
+ * "The only GL commands that are allowed within any Begin/End pairs are
+ * the commands for specifying vertex coordinates, vertex color, normal
+ * coordinates, and texture coordinates (Vertex, Color, Index, Normal,
+ * TexCoord), EvalCoord and EvalPoint commands (see section 5.1),
+ * commands for specifying lighting material parameters (Material
+ * commands see section 2.12.2), display list invocation commands
+ * (CallList and CallLists see section 5.4), and the EdgeFlag
+ * command. Executing Begin after Begin has already been executed but
+ * before an End is issued generates the INVALID OPERATION error, as does
+ * executing End without a previous corresponding Begin. Executing any
+ * other GL command within Begin/End results in the error INVALID
+ * OPERATION."
+ *
+ * The table entries for specifying vertex attributes are set up by
+ * install_vtxfmt() and _mesa_loopback_init_api_table(), and End() and dlists
+ * are set by install_vtxfmt() as well.
+ */
+static struct _glapi_table *
+create_beginend_table(const struct gl_context *ctx)
+{
+ struct _glapi_table *table;
+
+ table = _mesa_alloc_dispatch_table(_gloffset_COUNT);
+ if (!table)
+ return NULL;
+
+ /* Fill in functions which return a value, since they should return some
+ * specific value even if they emit a GL_INVALID_OPERATION error from them
+ * being called within glBegin()/glEnd().
+ */
+#define COPY_DISPATCH(func) SET_##func(table, GET_##func(ctx->Exec))
+
+ COPY_DISPATCH(GenLists);
+ COPY_DISPATCH(IsProgram);
+ COPY_DISPATCH(IsVertexArray);
+ COPY_DISPATCH(IsBuffer);
+ COPY_DISPATCH(IsEnabled);
+ COPY_DISPATCH(IsEnabledi);
+ COPY_DISPATCH(IsRenderbuffer);
+ COPY_DISPATCH(IsFramebuffer);
+ COPY_DISPATCH(CheckFramebufferStatus);
+ COPY_DISPATCH(RenderMode);
+ COPY_DISPATCH(GetString);
+ COPY_DISPATCH(GetStringi);
+ COPY_DISPATCH(GetPointerv);
+ COPY_DISPATCH(IsQuery);
+ COPY_DISPATCH(IsSampler);
+ COPY_DISPATCH(IsSync);
+ COPY_DISPATCH(IsTexture);
+ COPY_DISPATCH(IsTransformFeedback);
+ COPY_DISPATCH(DeleteQueries);
+ COPY_DISPATCH(AreTexturesResident);
+ COPY_DISPATCH(FenceSync);
+ COPY_DISPATCH(ClientWaitSync);
+ COPY_DISPATCH(MapBuffer);
+ COPY_DISPATCH(UnmapBuffer);
+ COPY_DISPATCH(MapBufferRange);
+ COPY_DISPATCH(MapBufferRange);
+ COPY_DISPATCH(ObjectPurgeableAPPLE);
+ COPY_DISPATCH(ObjectUnpurgeableAPPLE);
+
+ _mesa_loopback_init_api_table(ctx, table);
+
+ return table;
+}
/**
* Initialize a struct gl_context struct (rendering context).
@@ -933,19 +1009,15 @@ _mesa_initialize_context(struct gl_context *ctx,
_mesa_reference_shared_state(ctx, &ctx->Shared, shared);
- if (!init_attrib_groups( ctx )) {
- _mesa_reference_shared_state(ctx, &ctx->Shared, NULL);
- return GL_FALSE;
- }
+ if (!init_attrib_groups( ctx ))
+ goto fail;
/* setup the API dispatch tables with all nop functions */
- ctx->Exec = _mesa_alloc_dispatch_table(_gloffset_COUNT);
-
- if (!ctx->Exec) {
- _mesa_reference_shared_state(ctx, &ctx->Shared, NULL);
- return GL_FALSE;
- }
- ctx->CurrentDispatch = ctx->Exec;
+ ctx->OutsideBeginEnd = _mesa_alloc_dispatch_table(_gloffset_COUNT);
+ if (!ctx->OutsideBeginEnd)
+ goto fail;
+ ctx->Exec = ctx->OutsideBeginEnd;
+ ctx->CurrentDispatch = ctx->OutsideBeginEnd;
ctx->FragmentProgram._MaintainTexEnvProgram
= (_mesa_getenv("MESA_TEX_PROG") != NULL);
@@ -967,12 +1039,10 @@ _mesa_initialize_context(struct gl_context *ctx,
switch (ctx->API) {
case API_OPENGL_COMPAT:
+ ctx->BeginEnd = create_beginend_table(ctx);
ctx->Save = _mesa_create_save_table(ctx);
- if (!ctx->Save) {
- _mesa_reference_shared_state(ctx, &ctx->Shared, NULL);
- free(ctx->Exec);
- return GL_FALSE;
- }
+ if (!ctx->BeginEnd || !ctx->Save)
+ goto fail;
/* fall-through */
case API_OPENGL_CORE:
@@ -1002,6 +1072,12 @@ _mesa_initialize_context(struct gl_context *ctx,
ctx->FirstTimeCurrent = GL_TRUE;
return GL_TRUE;
+
+fail:
+ free(ctx->BeginEnd);
+ free(ctx->Exec);
+ free(ctx->Save);
+ return GL_FALSE;
}
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index cba1e1681a5..ead75d50eb5 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -3440,9 +3440,28 @@ struct gl_context
/** \name API function pointer tables */
/*@{*/
gl_api API;
- struct _glapi_table *Save; /**< Display list save functions */
- struct _glapi_table *Exec; /**< Execute functions */
- struct _glapi_table *CurrentDispatch; /**< == Save or Exec !! */
+ /**
+ * The current dispatch table for non-displaylist-saving execution, either
+ * BeginEnd or OutsideBeginEnd
+ */
+ struct _glapi_table *Exec;
+ /**
+ * The normal dispatch table for non-displaylist-saving, non-begin/end
+ */
+ struct _glapi_table *OutsideBeginEnd;
+ /** The dispatch table used between glNewList() and glEndList() */
+ struct _glapi_table *Save;
+ /**
+ * The dispatch table used between glBegin() and glEnd() (outside of a
+ * display list). Only valid functions between those two are set, which is
+ * mostly just the set in a GLvertexformat struct.
+ */
+ struct _glapi_table *BeginEnd;
+ /**
+ * Tracks the current dispatch table out of the 3 above, so that it can be
+ * re-set on glXMakeCurrent().
+ */
+ struct _glapi_table *CurrentDispatch;
/*@}*/
struct gl_config Visual;
diff --git a/src/mesa/main/vtxfmt.c b/src/mesa/main/vtxfmt.c
index 6d687de606b..347d07d5727 100644
--- a/src/mesa/main/vtxfmt.c
+++ b/src/mesa/main/vtxfmt.c
@@ -252,6 +252,8 @@ void
_mesa_install_exec_vtxfmt(struct gl_context *ctx, const GLvertexformat *vfmt)
{
install_vtxfmt( ctx, ctx->Exec, vfmt );
+ if (ctx->BeginEnd)
+ install_vtxfmt( ctx, ctx->BeginEnd, vfmt );
}
diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c
index 84bcdd63bf3..f9874396658 100644
--- a/src/mesa/vbo/vbo_exec_api.c
+++ b/src/mesa/vbo/vbo_exec_api.c
@@ -833,6 +833,17 @@ static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
exec->vtx.prim[i].base_instance = 0;
ctx->Driver.CurrentExecPrimitive = mode;
+
+ ctx->Exec = ctx->BeginEnd;
+ /* We may have been called from a display list, in which case we should
+ * leave dlist.c's dispatch table in place.
+ */
+ if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
+ ctx->CurrentDispatch = ctx->BeginEnd;
+ _glapi_set_dispatch(ctx->CurrentDispatch);
+ } else {
+ assert(ctx->CurrentDispatch == ctx->Save);
+ }
}
@@ -849,6 +860,12 @@ static void GLAPIENTRY vbo_exec_End( void )
return;
}
+ ctx->Exec = ctx->OutsideBeginEnd;
+ if (ctx->CurrentDispatch == ctx->BeginEnd) {
+ ctx->CurrentDispatch = ctx->OutsideBeginEnd;
+ _glapi_set_dispatch(ctx->CurrentDispatch);
+ }
+
if (exec->vtx.prim_count > 0) {
/* close off current primitive */
int idx = exec->vtx.vert_count;