[Mesa-dev] [PATCH 2/2] mesa: fix glMaterial / dlist bug

Brian Paul brianp at vmware.com
Tue May 8 12:16:00 PDT 2012


When glColorMaterial() is used to latch glColor commands to a material
attribute, glMaterial calls to change that material should become no-ops.
This failed to work properly when the glMaterial call was inside a
display list.

This removes the Material function from the vbo_attrib_tmp.h template
file.  We have separate/different implementations for the "save" and
"exec" cases now.

NOTE: This is a candidate for the 8.0 branch.
---
 src/mesa/vbo/vbo_attrib_tmp.h |   58 -------------------------
 src/mesa/vbo/vbo_exec_api.c   |   95 +++++++++++++++++++++++++++++++++++++++++
 src/mesa/vbo/vbo_save_api.c   |   57 ++++++++++++++++++++++++
 3 files changed, 152 insertions(+), 58 deletions(-)

diff --git a/src/mesa/vbo/vbo_attrib_tmp.h b/src/mesa/vbo/vbo_attrib_tmp.h
index 0bf5c91..d3fc77e 100644
--- a/src/mesa/vbo/vbo_attrib_tmp.h
+++ b/src/mesa/vbo/vbo_attrib_tmp.h
@@ -792,63 +792,6 @@ TAG(VertexAttrib4fvNV)(GLuint index, const GLfloat * v)
 }
 
 
-
-#define MAT( ATTR, N, face, params )			\
-do {							\
-   if (face != GL_BACK)					\
-      MAT_ATTR( ATTR, N, params ); /* front */		\
-   if (face != GL_FRONT)				\
-      MAT_ATTR( ATTR + 1, N, params ); /* back */	\
-} while (0)
-
-
-/* Colormaterial conflicts are dealt with later.
- */
-static void GLAPIENTRY
-TAG(Materialfv)(GLenum face, GLenum pname,
-                 const GLfloat * params)
-{
-   GET_CURRENT_CONTEXT(ctx);
-
-   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
-      return;
-   }
-
-   switch (pname) {
-   case GL_EMISSION:
-      MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
-      break;
-   case GL_AMBIENT:
-      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
-      break;
-   case GL_DIFFUSE:
-      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
-      break;
-   case GL_SPECULAR:
-      MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
-      break;
-   case GL_SHININESS:
-      if (*params < 0 || *params > ctx->Const.MaxShininess)
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glMaterial(invalid shininess: %f out range [0, %f])",
-		     *params, ctx->Const.MaxShininess);
-      else
-         MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
-      break;
-   case GL_COLOR_INDEXES:
-      MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
-      break;
-   case GL_AMBIENT_AND_DIFFUSE:
-      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
-      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
-      break;
-   default:
-      ERROR(GL_INVALID_ENUM);
-      return;
-   }
-}
-
 static void GLAPIENTRY
 TAG(VertexP2ui)(GLenum type, GLuint value)
 {
@@ -1145,4 +1088,3 @@ TAG(VertexAttribP4uiv)(GLuint index, GLenum type, GLboolean normalized,
 #undef ATTR_UI
 
 #undef MAT
-#undef MAT_ATTR
diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c
index b87da18..0fd8d59 100644
--- a/src/mesa/vbo/vbo_exec_api.c
+++ b/src/mesa/vbo/vbo_exec_api.c
@@ -433,6 +433,101 @@ do {									\
 #include "vbo_attrib_tmp.h"
 
 
+
+/**
+ * Execute a glMaterial call.  Note that if GL_COLOR_MATERIAL is enabled,
+ * this may be a (partial) no-op.
+ */
+static void GLAPIENTRY
+vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+   GLbitfield updateMats;
+   GET_CURRENT_CONTEXT(ctx);
+
+   /* This function should be a no-op when it tries to update material
+    * attributes which are currently tracking glColor via glColorMaterial.
+    * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
+    * indicating which material attributes can actually be updated below.
+    */
+   if (ctx->Light.ColorMaterialEnabled) {
+      updateMats = ~ctx->Light.ColorMaterialBitmask;
+   }
+   else {
+      /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
+      updateMats = ALL_MATERIAL_BITS;
+   }
+
+   if (face == GL_FRONT) {
+      updateMats &= FRONT_MATERIAL_BITS;
+   }
+   else if (face == GL_BACK) {
+      updateMats &= BACK_MATERIAL_BITS;
+   }
+   else if (face != GL_FRONT_AND_BACK) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
+      return;
+   }
+
+   switch (pname) {
+   case GL_EMISSION:
+      if (updateMats & MAT_BIT_FRONT_EMISSION)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
+      if (updateMats & MAT_BIT_BACK_EMISSION)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
+      break;
+   case GL_AMBIENT:
+      if (updateMats & MAT_BIT_FRONT_AMBIENT)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
+      if (updateMats & MAT_BIT_BACK_AMBIENT)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
+      break;
+   case GL_DIFFUSE:
+      if (updateMats & MAT_BIT_FRONT_DIFFUSE)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
+      if (updateMats & MAT_BIT_BACK_DIFFUSE)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
+      break;
+   case GL_SPECULAR:
+      if (updateMats & MAT_BIT_FRONT_SPECULAR)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
+      if (updateMats & MAT_BIT_BACK_SPECULAR)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
+      break;
+   case GL_SHININESS:
+      if (*params < 0 || *params > ctx->Const.MaxShininess) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glMaterial(invalid shininess: %f out range [0, %f])",
+		     *params, ctx->Const.MaxShininess);
+         return;
+      }
+      if (updateMats & MAT_BIT_FRONT_SHININESS)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
+      if (updateMats & MAT_BIT_BACK_SHININESS)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
+      break;
+   case GL_COLOR_INDEXES:
+      if (updateMats & MAT_BIT_FRONT_INDEXES)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
+      if (updateMats & MAT_BIT_BACK_INDEXES)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
+      break;
+   case GL_AMBIENT_AND_DIFFUSE:
+      if (updateMats & MAT_BIT_FRONT_AMBIENT)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
+      if (updateMats & MAT_BIT_FRONT_DIFFUSE)
+         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
+      if (updateMats & MAT_BIT_BACK_AMBIENT)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
+      if (updateMats & MAT_BIT_BACK_DIFFUSE)
+         MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
+      break;
+   default:
+      _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
+      return;
+   }
+}
+
+
 /**
  * Flush (draw) vertices.
  * \param  unmap - leave VBO unmapped after flushing?
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index 74f5dc9..f202375 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -724,6 +724,63 @@ do {								\
 
 
 
+#define MAT( ATTR, N, face, params )			\
+do {							\
+   if (face != GL_BACK)					\
+      MAT_ATTR( ATTR, N, params ); /* front */		\
+   if (face != GL_FRONT)				\
+      MAT_ATTR( ATTR + 1, N, params ); /* back */	\
+} while (0)
+
+
+/**
+ * Save a glMaterial call found between glBegin/End.
+ * glMaterial calls outside Begin/End are handled in dlist.c.
+ */
+static void GLAPIENTRY
+_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
+      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
+      return;
+   }
+
+   switch (pname) {
+   case GL_EMISSION:
+      MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
+      break;
+   case GL_AMBIENT:
+      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
+      break;
+   case GL_DIFFUSE:
+      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
+      break;
+   case GL_SPECULAR:
+      MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
+      break;
+   case GL_SHININESS:
+      if (*params < 0 || *params > ctx->Const.MaxShininess) {
+         _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
+      }
+      else {
+         MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
+      }
+      break;
+   case GL_COLOR_INDEXES:
+      MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
+      break;
+   case GL_AMBIENT_AND_DIFFUSE:
+      MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
+      MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
+      break;
+   default:
+      _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
+      return;
+   }
+}
+
 
 /* Cope with EvalCoord/CallList called within a begin/end object:
  *     -- Flush current buffer
-- 
1.7.3.4



More information about the mesa-dev mailing list