Mesa (intel-2008-q4): intel: Add support for glBitmap as metaops using GL calls.

Haihao Xiang haihao at kemper.freedesktop.org
Mon Jan 5 08:06:23 UTC 2009


Module: Mesa
Branch: intel-2008-q4
Commit: 425ede63089b1a13c9ef74d6b76b07501827fbb7
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=425ede63089b1a13c9ef74d6b76b07501827fbb7

Author: Eric Anholt <eric at anholt.net>
Date:   Wed Dec 31 00:02:43 2008 -0800

intel: Add support for glBitmap as metaops using GL calls.

This lets us avoid software fallbacks when clients forget to turn some state
off (engine demo) or just do crazy things to test conformance (OGLC).

This should probably be brought into mesa generic code so other drivers can
make use of it.

Bug #19016.
(cherry picked from commit e1a92175542c6645c23cc78f2a4fcd36dd0235e6)

---

 src/mesa/drivers/dri/intel/intel_context.h      |   10 ++
 src/mesa/drivers/dri/intel/intel_pixel.c        |  133 +++++++++++++++
 src/mesa/drivers/dri/intel/intel_pixel.h        |    8 +
 src/mesa/drivers/dri/intel/intel_pixel_bitmap.c |  199 +++++++++++++++++++++++
 4 files changed, 350 insertions(+), 0 deletions(-)

diff --git a/src/mesa/drivers/dri/intel/intel_context.h b/src/mesa/drivers/dri/intel/intel_context.h
index ee43ed7..4d0ae0e 100644
--- a/src/mesa/drivers/dri/intel/intel_context.h
+++ b/src/mesa/drivers/dri/intel/intel_context.h
@@ -157,6 +157,16 @@ struct intel_context
       void (*debug_batch)(struct intel_context *intel);
    } vtbl;
 
+   struct {
+      struct gl_fragment_program *bitmap_fp;
+      struct gl_vertex_program *passthrough_vp;
+
+      struct gl_fragment_program *saved_fp;
+      GLboolean saved_fp_enable;
+      struct gl_vertex_program *saved_vp;
+      GLboolean saved_vp_enable;
+   } meta;
+
    GLint refcount;
    GLuint Fallback;
    GLuint NewGLState;
diff --git a/src/mesa/drivers/dri/intel/intel_pixel.c b/src/mesa/drivers/dri/intel/intel_pixel.c
index 5702ad9..91027d3 100644
--- a/src/mesa/drivers/dri/intel/intel_pixel.c
+++ b/src/mesa/drivers/dri/intel/intel_pixel.c
@@ -27,7 +27,11 @@
 
 #include "main/enums.h"
 #include "main/state.h"
+#include "main/context.h"
+#include "main/enable.h"
 #include "swrast/swrast.h"
+#include "shader/arbprogram.h"
+#include "shader/program.h"
 
 #include "intel_context.h"
 #include "intel_pixel.h"
@@ -167,6 +171,125 @@ intel_check_blit_format(struct intel_region * region,
    return GL_FALSE;
 }
 
+/**
+ * Set up a vertex program to pass through the position and first texcoord
+ * for pixel path.
+ */
+void
+intel_meta_set_passthrough_vertex_program(struct intel_context *intel)
+{
+   GLcontext *ctx = &intel->ctx;
+   static const char *vp =
+      "!!ARBvp1.0\n"
+      "TEMP vertexClip;\n"
+      "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position;\n"
+      "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position;\n"
+      "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position;\n"
+      "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position;\n"
+      "MOV result.position, vertexClip;\n"
+      "MOV result.texcoord[0], vertex.texcoord[0];\n"
+      "MOV result.color, vertex.color;\n"
+      "END\n";
+
+   assert(intel->meta.saved_vp == NULL);
+
+   _mesa_reference_vertprog(ctx, &intel->meta.saved_vp,
+			    ctx->VertexProgram.Current);
+   if (intel->meta.passthrough_vp == NULL) {
+      GLuint prog_name;
+      _mesa_GenPrograms(1, &prog_name);
+      _mesa_BindProgram(GL_VERTEX_PROGRAM_ARB, prog_name);
+      _mesa_ProgramStringARB(GL_VERTEX_PROGRAM_ARB,
+			     GL_PROGRAM_FORMAT_ASCII_ARB,
+			     strlen(vp), (const GLubyte *)vp);
+      _mesa_reference_vertprog(ctx, &intel->meta.passthrough_vp,
+			       ctx->VertexProgram.Current);
+      _mesa_DeletePrograms(1, &prog_name);
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+			    intel->meta.passthrough_vp);
+   ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
+			   &intel->meta.passthrough_vp->Base);
+
+   intel->meta.saved_vp_enable = ctx->VertexProgram.Enabled;
+   _mesa_Enable(GL_VERTEX_PROGRAM_ARB);
+}
+
+/**
+ * Restores the previous vertex program after
+ * intel_meta_set_passthrough_vertex_program()
+ */
+void
+intel_meta_restore_vertex_program(struct intel_context *intel)
+{
+   GLcontext *ctx = &intel->ctx;
+
+   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+   _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+			    intel->meta.saved_vp);
+   _mesa_reference_vertprog(ctx, &intel->meta.saved_vp, NULL);
+   ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
+			   &ctx->VertexProgram.Current->Base);
+
+   if (!intel->meta.saved_vp_enable)
+      _mesa_Disable(GL_VERTEX_PROGRAM_ARB);
+}
+
+/**
+ * Binds the given program string to GL_FRAGMENT_PROGRAM_ARB, caching the
+ * program object.
+ */
+void
+intel_meta_set_fragment_program(struct intel_context *intel,
+				struct gl_fragment_program **prog,
+				const char *prog_string)
+{
+   GLcontext *ctx = &intel->ctx;
+   assert(intel->meta.saved_fp == NULL);
+
+   _mesa_reference_fragprog(ctx, &intel->meta.saved_fp,
+			    ctx->FragmentProgram.Current);
+   if (*prog == NULL) {
+      GLuint prog_name;
+      _mesa_GenPrograms(1, &prog_name);
+      _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, prog_name);
+      _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
+			     GL_PROGRAM_FORMAT_ASCII_ARB,
+			     strlen(prog_string), (const GLubyte *)prog_string);
+      _mesa_reference_fragprog(ctx, prog, ctx->FragmentProgram.Current);
+      /* Note that DeletePrograms unbinds the program on us */
+      _mesa_DeletePrograms(1, &prog_name);
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, *prog);
+   ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, &((*prog)->Base));
+
+   intel->meta.saved_fp_enable = ctx->FragmentProgram.Enabled;
+   _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB);
+}
+
+/**
+ * Restores the previous fragment program after
+ * intel_meta_set_fragment_program()
+ */
+void
+intel_meta_restore_fragment_program(struct intel_context *intel)
+{
+   GLcontext *ctx = &intel->ctx;
+
+   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+   _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+			    intel->meta.saved_fp);
+   _mesa_reference_fragprog(ctx, &intel->meta.saved_fp, NULL);
+   ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB,
+			   &ctx->FragmentProgram.Current->Base);
+
+   if (!intel->meta.saved_fp_enable)
+      _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB);
+}
 
 void
 intelInitPixelFuncs(struct dd_function_table *functions)
@@ -181,3 +304,13 @@ intelInitPixelFuncs(struct dd_function_table *functions)
 #endif
    }
 }
+
+void
+intel_free_pixel_state(struct intel_context *intel)
+{
+   GLcontext *ctx = &intel->ctx;
+
+   _mesa_reference_vertprog(ctx, &intel->meta.passthrough_vp, NULL);
+   _mesa_reference_fragprog(ctx, &intel->meta.bitmap_fp, NULL);
+}
+
diff --git a/src/mesa/drivers/dri/intel/intel_pixel.h b/src/mesa/drivers/dri/intel/intel_pixel.h
index 6fa6eff..9556efc 100644
--- a/src/mesa/drivers/dri/intel/intel_pixel.h
+++ b/src/mesa/drivers/dri/intel/intel_pixel.h
@@ -32,6 +32,14 @@
 
 void intelInitPixelFuncs(struct dd_function_table *functions);
 
+void intel_meta_set_passthrough_vertex_program(struct intel_context *intel);
+void intel_meta_restore_vertex_program(struct intel_context *intel);
+void intel_meta_set_fragment_program(struct intel_context *intel,
+				     struct gl_fragment_program **prog,
+				     const char *prog_string);
+void intel_meta_restore_fragment_program(struct intel_context *intel);
+void intel_free_pixel_state(struct intel_context *intel);
+
 GLboolean intel_check_blit_fragment_ops(GLcontext * ctx,
 					GLboolean src_alpha_is_one);
 
diff --git a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c
index 5e0e0d2..88e181a 100644
--- a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c
+++ b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c
@@ -32,7 +32,19 @@
 #include "main/mtypes.h"
 #include "main/macros.h"
 #include "main/bufferobj.h"
+#include "main/pixelstore.h"
 #include "main/state.h"
+#include "main/teximage.h"
+#include "main/texenv.h"
+#include "main/texobj.h"
+#include "main/texstate.h"
+#include "main/texparam.h"
+#include "main/matrix.h"
+#include "main/varray.h"
+#include "main/attrib.h"
+#include "main/enable.h"
+#include "shader/arbprogram.h"
+#include "glapi/dispatch.h"
 #include "swrast/swrast.h"
 
 #include "intel_screen.h"
@@ -87,6 +99,11 @@ static GLboolean test_bit( const GLubyte *src,
    return (src[bit/8] & (1<<(bit % 8))) ? 1 : 0;
 }
 
+static GLboolean test_msb_bit(const GLubyte *src, GLuint bit)
+{
+   return (src[bit/8] & (1<<(7 - (bit % 8)))) ? 1 : 0;
+}
+
 static void set_bit( GLubyte *dest,
 			  GLuint bit )
 {
@@ -317,9 +334,187 @@ out:
    return GL_TRUE;
 }
 
+static GLboolean
+intel_texture_bitmap(GLcontext * ctx,
+		     GLint dst_x, GLint dst_y,
+		     GLsizei width, GLsizei height,
+		     const struct gl_pixelstore_attrib *unpack,
+		     const GLubyte *bitmap)
+{
+   struct intel_context *intel = intel_context(ctx);
+   static const char *fp =
+      "!!ARBfp1.0\n"
+      "TEMP val;\n"
+      "PARAM color=program.local[0];\n"
+      "TEX val, fragment.texcoord[0], texture[0], 2D;\n"
+      "ADD val, val.wwww, {-.5, -.5, -.5, -.5};\n"
+      "KIL val;\n"
+      "MOV result.color, color;\n"
+      "END\n";
+   GLuint texname;
+   GLfloat vertices[4][4];
+   GLfloat texcoords[4][2];
+   GLint old_active_texture;
+   GLubyte *unpacked_bitmap;
+   GLubyte *a8_bitmap;
+   int x, y;
+
+   /* We need a fragment program for the KIL effect */
+   if (!ctx->Extensions.ARB_fragment_program ||
+       !ctx->Extensions.ARB_vertex_program) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+	 fprintf(stderr,
+		 "glBitmap fallback: No fragment/vertex program support\n");
+      return GL_FALSE;
+   }
+
+   /* We're going to mess with texturing with no regard to existing texture
+    * state, so if there is some set up we have to bail.
+    */
+   if (ctx->Texture._EnabledUnits != 0) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+	 fprintf(stderr, "glBitmap fallback: texturing enabled\n");
+      return GL_FALSE;
+   }
+
+   /* Can't do textured DrawPixels with a fragment program, unless we were
+    * to generate a new program that sampled our texture and put the results
+    * in the fragment color before the user's program started.
+    */
+   if (ctx->FragmentProgram.Enabled) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+	 fprintf(stderr, "glBitmap fallback: fragment program enabled\n");
+      return GL_FALSE;
+   }
+
+   if (ctx->VertexProgram.Enabled) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+	 fprintf(stderr, "glBitmap fallback: vertex program enabled\n");
+      return GL_FALSE;
+   }
+
+   /* Check that we can load in a texture this big. */
+   if (width > (1 << (ctx->Const.MaxTextureLevels - 1)) ||
+       height > (1 << (ctx->Const.MaxTextureLevels - 1))) {
+      if (INTEL_DEBUG & DEBUG_FALLBACKS)
+	 fprintf(stderr, "glBitmap fallback: bitmap too large (%dx%d)\n",
+		 width, height);
+      return GL_FALSE;
+   }
 
+   /* Convert the A1 bitmap to an A8 format suitable for glTexImage */
+   if (unpack->BufferObj->Name) {
+      bitmap = map_pbo(ctx, width, height, unpack, bitmap);
+      if (bitmap == NULL)
+	 return GL_TRUE;	/* even though this is an error, we're done */
+   }
+   unpacked_bitmap = _mesa_unpack_bitmap(width, height, bitmap,
+					 unpack);
+   a8_bitmap = _mesa_calloc(width * height);
+   for (y = 0; y < height; y++) {
+      for (x = 0; x < width; x++) {
+	 if (test_msb_bit(unpacked_bitmap, ALIGN(width, 8) * y + x))
+	    a8_bitmap[y * width + x] = 0xff;
+      }
+   }
+   _mesa_free(unpacked_bitmap);
+   if (unpack->BufferObj->Name) {
+      /* done with PBO so unmap it now */
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                              unpack->BufferObj);
+   }
 
+   /* Save GL state before we start setting up our drawing */
+   _mesa_PushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_CURRENT_BIT |
+		    GL_VIEWPORT_BIT);
+   _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT |
+			  GL_CLIENT_PIXEL_STORE_BIT);
+   old_active_texture = ctx->Texture.CurrentUnit;
+
+   _mesa_Disable(GL_POLYGON_STIPPLE);
+
+   /* Upload our bitmap data to an alpha texture */
+   _mesa_ActiveTextureARB(GL_TEXTURE0_ARB);
+   _mesa_Enable(GL_TEXTURE_2D);
+   _mesa_GenTextures(1, &texname);
+   _mesa_BindTexture(GL_TEXTURE_2D, texname);
+   _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+   _mesa_PixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+   _mesa_PixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+   _mesa_PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+   _mesa_PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+   _mesa_PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+   _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   _mesa_TexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
+		    GL_ALPHA, GL_UNSIGNED_BYTE, a8_bitmap);
+   _mesa_free(a8_bitmap);
+
+   _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
+   _mesa_MatrixMode(GL_PROJECTION);
+   _mesa_PushMatrix();
+   _mesa_LoadIdentity();
+   _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1);
+
+   _mesa_MatrixMode(GL_MODELVIEW);
+   _mesa_PushMatrix();
+   _mesa_LoadIdentity();
+
+   intel_meta_set_fragment_program(intel, &intel->meta.bitmap_fp, fp);
+   _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0,
+				     ctx->Current.RasterColor);
+   intel_meta_set_passthrough_vertex_program(intel);
+
+   vertices[0][0] = dst_x;
+   vertices[0][1] = dst_y;
+   vertices[0][2] = ctx->Current.RasterPos[2];
+   vertices[0][3] = 1.0;
+   vertices[1][0] = dst_x + width;
+   vertices[1][1] = dst_y;
+   vertices[1][2] = ctx->Current.RasterPos[2];
+   vertices[1][3] = 1.0;
+   vertices[2][0] = dst_x + width;
+   vertices[2][1] = dst_y + height;
+   vertices[2][2] = ctx->Current.RasterPos[2];
+   vertices[2][3] = 1.0;
+   vertices[3][0] = dst_x;
+   vertices[3][1] = dst_y + height;
+   vertices[3][2] = ctx->Current.RasterPos[2];
+   vertices[3][3] = 1.0;
+
+   texcoords[0][0] = 0.0;
+   texcoords[0][1] = 0.0;
+   texcoords[1][0] = 1.0;
+   texcoords[1][1] = 0.0;
+   texcoords[2][0] = 1.0;
+   texcoords[2][1] = 1.0;
+   texcoords[3][0] = 0.0;
+   texcoords[3][1] = 1.0;
+
+   _mesa_VertexPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &vertices);
+   _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &texcoords);
+   _mesa_Enable(GL_VERTEX_ARRAY);
+   _mesa_Enable(GL_TEXTURE_COORD_ARRAY);
+   CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4));
+
+   intel_meta_restore_fragment_program(intel);
+   intel_meta_restore_vertex_program(intel);
+
+   _mesa_MatrixMode(GL_PROJECTION);
+   _mesa_PopMatrix();
+   _mesa_MatrixMode(GL_MODELVIEW);
+   _mesa_PopMatrix();
+
+   _mesa_PopClientAttrib();
+   _mesa_Disable(GL_TEXTURE_2D); /* asserted that it was disabled at entry */
+   _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture);
+   _mesa_PopAttrib();
+
+   _mesa_DeleteTextures(1, &texname);
 
+   return GL_TRUE;
+}
 
 /* There are a large number of possible ways to implement bitmap on
  * this hardware, most of them have some sort of drawback.  Here are a
@@ -352,6 +547,10 @@ intelBitmap(GLcontext * ctx,
                           unpack, pixels))
       return;
 
+   if (intel_texture_bitmap(ctx, x, y, width, height,
+			    unpack, pixels))
+      return;
+
    if (INTEL_DEBUG & DEBUG_PIXEL)
       _mesa_printf("%s: fallback to swrast\n", __FUNCTION__);
 




More information about the mesa-commit mailing list