PBO support for gl[Get]PixelMap functions
authorBrian Paul <brian.paul@tungstengraphics.com>
Sun, 31 Oct 2004 18:31:07 +0000 (18:31 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Sun, 31 Oct 2004 18:31:07 +0000 (18:31 +0000)
src/mesa/main/pixel.c

index 932dfce..3d36c66 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.1
+ * Version:  6.3
  *
  * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
  *
  */
 
 #include "glheader.h"
-#include "imports.h"
-#include "image.h"
+#include "bufferobj.h"
 #include "colormac.h"
 #include "context.h"
+#include "image.h"
 #include "macros.h"
 #include "pixel.h"
 #include "mtypes.h"
@@ -253,45 +253,29 @@ _mesa_PixelStoref( GLenum pname, GLfloat param )
 /**********************************************************************/
 
 
-
-void GLAPIENTRY
-_mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
+/**
+ * Helper routine used by the other _mesa_PixelMap() functions.
+ */
+static void
+pixelmap(GLcontext *ctx, GLenum map, GLsizei mapsize, const GLfloat *values)
 {
    GLint i;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
-      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
-      return;
-   }
-
-   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
-      /* test that mapsize is a power of two */
-      if (_mesa_bitcount((GLuint) mapsize) != 1) {
-        _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
-         return;
-      }
-   }
-
-   FLUSH_VERTICES(ctx, _NEW_PIXEL);
-
    switch (map) {
       case GL_PIXEL_MAP_S_TO_S:
          ctx->Pixel.MapStoSsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            ctx->Pixel.MapStoS[i] = (GLint) values[i];
         }
         break;
       case GL_PIXEL_MAP_I_TO_I:
          ctx->Pixel.MapItoIsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            ctx->Pixel.MapItoI[i] = (GLint) values[i];
         }
         break;
       case GL_PIXEL_MAP_I_TO_R:
          ctx->Pixel.MapItoRsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
             GLfloat val = CLAMP( values[i], 0.0F, 1.0F );
            ctx->Pixel.MapItoR[i] = val;
            ctx->Pixel.MapItoR8[i] = (GLint) (val * 255.0F);
@@ -299,7 +283,7 @@ _mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
         break;
       case GL_PIXEL_MAP_I_TO_G:
          ctx->Pixel.MapItoGsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
             GLfloat val = CLAMP( values[i], 0.0F, 1.0F );
            ctx->Pixel.MapItoG[i] = val;
            ctx->Pixel.MapItoG8[i] = (GLint) (val * 255.0F);
@@ -307,7 +291,7 @@ _mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
         break;
       case GL_PIXEL_MAP_I_TO_B:
          ctx->Pixel.MapItoBsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
             GLfloat val = CLAMP( values[i], 0.0F, 1.0F );
            ctx->Pixel.MapItoB[i] = val;
            ctx->Pixel.MapItoB8[i] = (GLint) (val * 255.0F);
@@ -315,7 +299,7 @@ _mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
         break;
       case GL_PIXEL_MAP_I_TO_A:
          ctx->Pixel.MapItoAsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
             GLfloat val = CLAMP( values[i], 0.0F, 1.0F );
            ctx->Pixel.MapItoA[i] = val;
            ctx->Pixel.MapItoA8[i] = (GLint) (val * 255.0F);
@@ -323,30 +307,89 @@ _mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
         break;
       case GL_PIXEL_MAP_R_TO_R:
          ctx->Pixel.MapRtoRsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            ctx->Pixel.MapRtoR[i] = CLAMP( values[i], 0.0F, 1.0F );
         }
         break;
       case GL_PIXEL_MAP_G_TO_G:
          ctx->Pixel.MapGtoGsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            ctx->Pixel.MapGtoG[i] = CLAMP( values[i], 0.0F, 1.0F );
         }
         break;
       case GL_PIXEL_MAP_B_TO_B:
          ctx->Pixel.MapBtoBsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            ctx->Pixel.MapBtoB[i] = CLAMP( values[i], 0.0F, 1.0F );
         }
         break;
       case GL_PIXEL_MAP_A_TO_A:
          ctx->Pixel.MapAtoAsize = mapsize;
-         for (i=0;i<mapsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            ctx->Pixel.MapAtoA[i] = CLAMP( values[i], 0.0F, 1.0F );
         }
         break;
       default:
-         _mesa_error( ctx, GL_INVALID_ENUM, "glPixelMapfv(map)" );
+         _mesa_error( ctx, GL_INVALID_ENUM, "glPixelMap(map)" );
+   }
+}
+
+
+void GLAPIENTRY
+_mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   /* XXX someday, test against ctx->Const.MaxPixelMapTableSize */
+   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
+      return;
+   }
+
+   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
+      /* test that mapsize is a power of two */
+      if (_mesa_bitcount((GLuint) mapsize) != 1) {
+        _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
+         return;
+      }
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_PIXEL);
+
+   if (ctx->Unpack.BufferObj->Name) {
+      /* unpack pixelmap from PBO */
+      GLubyte *buf;
+      /* Note, need to use DefaultPacking and Unpack's buffer object */
+      ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj;
+      if (!_mesa_validate_pbo_access(&ctx->DefaultPacking, mapsize, 1, 1,
+                                     GL_INTENSITY, GL_FLOAT, values)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glPixelMapfv(invalid PBO access)");
+         return;
+      }
+      /* restore */
+      ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj;
+      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                                              GL_READ_ONLY_ARB,
+                                              ctx->Unpack.BufferObj);
+      if (!buf) {
+         /* buffer is already mapped - that's an error */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glPixelMapfv(PBO is mapped)");
+         return;
+      }
+      values = (const GLfloat *) ADD_POINTERS(buf, values);
+   }
+   else if (!values) {
+      return;
+   }
+
+   pixelmap(ctx, map, mapsize, values);
+
+   if (ctx->Unpack.BufferObj->Name) {
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                              ctx->Unpack.BufferObj);
    }
 }
 
@@ -355,20 +398,73 @@ _mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
 void GLAPIENTRY
 _mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values )
 {
-   const GLint n = MIN2(mapsize, MAX_PIXEL_MAP_TABLE);
    GLfloat fvalues[MAX_PIXEL_MAP_TABLE];
-   GLint i;
-   if (map==GL_PIXEL_MAP_I_TO_I || map==GL_PIXEL_MAP_S_TO_S) {
-      for (i=0;i<n;i++) {
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
+      return;
+   }
+
+   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
+      /* test that mapsize is a power of two */
+      if (_mesa_bitcount((GLuint) mapsize) != 1) {
+        _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
+         return;
+      }
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_PIXEL);
+
+   if (ctx->Unpack.BufferObj->Name) {
+      /* unpack pixelmap from PBO */
+      GLubyte *buf;
+      /* Note, need to use DefaultPacking and Unpack's buffer object */
+      ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj;
+      if (!_mesa_validate_pbo_access(&ctx->DefaultPacking, mapsize, 1, 1,
+                                     GL_INTENSITY, GL_UNSIGNED_INT, values)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glPixelMapuiv(invalid PBO access)");
+         return;
+      }
+      /* restore */
+      ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj;
+      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                                              GL_READ_ONLY_ARB,
+                                              ctx->Unpack.BufferObj);
+      if (!buf) {
+         /* buffer is already mapped - that's an error */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glPixelMapuiv(PBO is mapped)");
+         return;
+      }
+      values = (const GLuint *) ADD_POINTERS(buf, values);
+   }
+   else if (!values) {
+      return;
+   }
+
+   /* convert to floats */
+   if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) {
+      GLint i;
+      for (i = 0; i < mapsize; i++) {
          fvalues[i] = (GLfloat) values[i];
       }
    }
    else {
-      for (i=0;i<n;i++) {
+      GLint i;
+      for (i = 0; i < mapsize; i++) {
          fvalues[i] = UINT_TO_FLOAT( values[i] );
       }
    }
-   _mesa_PixelMapfv(map, mapsize, fvalues);
+
+   if (ctx->Unpack.BufferObj->Name) {
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                              ctx->Unpack.BufferObj);
+   }
+
+   pixelmap(ctx, map, mapsize, fvalues);
 }
 
 
@@ -376,69 +472,190 @@ _mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values )
 void GLAPIENTRY
 _mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values )
 {
-   const GLint n = MIN2(mapsize, MAX_PIXEL_MAP_TABLE);
    GLfloat fvalues[MAX_PIXEL_MAP_TABLE];
-   GLint i;
-   if (map==GL_PIXEL_MAP_I_TO_I || map==GL_PIXEL_MAP_S_TO_S) {
-      for (i=0;i<n;i++) {
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" );
+      return;
+   }
+
+   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
+      /* test that mapsize is a power of two */
+      if (_mesa_bitcount((GLuint) mapsize) != 1) {
+        _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
+         return;
+      }
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_PIXEL);
+
+   if (ctx->Unpack.BufferObj->Name) {
+      /* unpack pixelmap from PBO */
+      GLubyte *buf;
+      /* Note, need to use DefaultPacking and Unpack's buffer object */
+      ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj;
+      if (!_mesa_validate_pbo_access(&ctx->DefaultPacking, mapsize, 1, 1,
+                                     GL_INTENSITY, GL_UNSIGNED_SHORT,
+                                     values)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glPixelMapusv(invalid PBO access)");
+         return;
+      }
+      /* restore */
+      ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj;
+      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                                              GL_READ_ONLY_ARB,
+                                              ctx->Unpack.BufferObj);
+      if (!buf) {
+         /* buffer is already mapped - that's an error */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glPixelMapusv(PBO is mapped)");
+         return;
+      }
+      values = (const GLushort *) ADD_POINTERS(buf, values);
+   }
+   else if (!values) {
+      return;
+   }
+
+    /* convert to floats */
+   if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) {
+      GLint i;
+      for (i = 0; i < mapsize; i++) {
          fvalues[i] = (GLfloat) values[i];
       }
    }
    else {
-      for (i=0;i<n;i++) {
+      GLint i;
+      for (i = 0; i < mapsize; i++) {
          fvalues[i] = USHORT_TO_FLOAT( values[i] );
       }
    }
-   _mesa_PixelMapfv(map, mapsize, fvalues);
+
+   if (ctx->Unpack.BufferObj->Name) {
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
+                              ctx->Unpack.BufferObj);
+   }
+
+   pixelmap(ctx, map, mapsize, fvalues);
 }
 
 
+/**
+ * Return size of the named map.
+ */
+static GLuint
+get_map_size(GLcontext *ctx, GLenum map)
+{
+   switch (map) {
+      case GL_PIXEL_MAP_I_TO_I:
+         return ctx->Pixel.MapItoIsize;
+      case GL_PIXEL_MAP_S_TO_S:
+         return ctx->Pixel.MapStoSsize;
+      case GL_PIXEL_MAP_I_TO_R:
+         return ctx->Pixel.MapItoRsize;
+      case GL_PIXEL_MAP_I_TO_G:
+         return ctx->Pixel.MapItoGsize;
+      case GL_PIXEL_MAP_I_TO_B:
+         return ctx->Pixel.MapItoBsize;
+      case GL_PIXEL_MAP_I_TO_A:
+         return ctx->Pixel.MapItoAsize;
+      case GL_PIXEL_MAP_R_TO_R:
+         return ctx->Pixel.MapRtoRsize;
+      case GL_PIXEL_MAP_G_TO_G:
+         return ctx->Pixel.MapGtoGsize;
+      case GL_PIXEL_MAP_B_TO_B:
+         return ctx->Pixel.MapBtoBsize;
+      case GL_PIXEL_MAP_A_TO_A:
+         return ctx->Pixel.MapAtoAsize;
+      default:
+         return 0;
+   }
+}
+
 
 void GLAPIENTRY
 _mesa_GetPixelMapfv( GLenum map, GLfloat *values )
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLint i;
+   GLuint mapsize, i;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   mapsize = get_map_size(ctx, map);
+
+   if (ctx->Pack.BufferObj->Name) {
+      /* pack pixelmap into PBO */
+      GLubyte *buf;
+      /* Note, need to use DefaultPacking and Pack's buffer object */
+      ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj;
+      if (!_mesa_validate_pbo_access(&ctx->DefaultPacking, mapsize, 1, 1,
+                                     GL_INTENSITY, GL_FLOAT, values)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetPixelMapfv(invalid PBO access)");
+         return;
+      }
+      /* restore */
+      ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj;
+      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
+                                              GL_WRITE_ONLY_ARB,
+                                              ctx->Pack.BufferObj);
+      if (!buf) {
+         /* buffer is already mapped - that's an error */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetPixelMapfv(PBO is mapped)");
+         return;
+      }
+      values = (GLfloat *) ADD_POINTERS(buf, values);
+   }
+   else if (!values) {
+      return;
+   }
+
    switch (map) {
       case GL_PIXEL_MAP_I_TO_I:
-         for (i=0;i<ctx->Pixel.MapItoIsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            values[i] = (GLfloat) ctx->Pixel.MapItoI[i];
         }
         break;
       case GL_PIXEL_MAP_S_TO_S:
-         for (i=0;i<ctx->Pixel.MapStoSsize;i++) {
+         for (i = 0; i < mapsize; i++) {
            values[i] = (GLfloat) ctx->Pixel.MapStoS[i];
         }
         break;
       case GL_PIXEL_MAP_I_TO_R:
-         MEMCPY(values,ctx->Pixel.MapItoR,ctx->Pixel.MapItoRsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapItoR, mapsize * sizeof(GLfloat));
         break;
       case GL_PIXEL_MAP_I_TO_G:
-         MEMCPY(values,ctx->Pixel.MapItoG,ctx->Pixel.MapItoGsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapItoG, mapsize * sizeof(GLfloat));
         break;
       case GL_PIXEL_MAP_I_TO_B:
-         MEMCPY(values,ctx->Pixel.MapItoB,ctx->Pixel.MapItoBsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapItoB, mapsize * sizeof(GLfloat));
         break;
       case GL_PIXEL_MAP_I_TO_A:
-         MEMCPY(values,ctx->Pixel.MapItoA,ctx->Pixel.MapItoAsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapItoA, mapsize * sizeof(GLfloat));
         break;
       case GL_PIXEL_MAP_R_TO_R:
-         MEMCPY(values,ctx->Pixel.MapRtoR,ctx->Pixel.MapRtoRsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapRtoR, mapsize * sizeof(GLfloat));
         break;
       case GL_PIXEL_MAP_G_TO_G:
-         MEMCPY(values,ctx->Pixel.MapGtoG,ctx->Pixel.MapGtoGsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapGtoG, mapsize * sizeof(GLfloat));
         break;
       case GL_PIXEL_MAP_B_TO_B:
-         MEMCPY(values,ctx->Pixel.MapBtoB,ctx->Pixel.MapBtoBsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapBtoB, mapsize * sizeof(GLfloat));
         break;
       case GL_PIXEL_MAP_A_TO_A:
-         MEMCPY(values,ctx->Pixel.MapAtoA,ctx->Pixel.MapAtoAsize*sizeof(GLfloat));
+         MEMCPY(values, ctx->Pixel.MapAtoA, mapsize * sizeof(GLfloat));
         break;
       default:
          _mesa_error( ctx, GL_INVALID_ENUM, "glGetPixelMapfv" );
    }
+
+   if (ctx->Pack.BufferObj->Name) {
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
+                              ctx->Pack.BufferObj);
+   }
 }
 
 
@@ -446,59 +663,94 @@ void GLAPIENTRY
 _mesa_GetPixelMapuiv( GLenum map, GLuint *values )
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLint i;
+   GLint mapsize, i;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   mapsize = get_map_size(ctx, map);
+
+   if (ctx->Pack.BufferObj->Name) {
+      /* pack pixelmap into PBO */
+      GLubyte *buf;
+      /* Note, need to use DefaultPacking and Pack's buffer object */
+      ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj;
+      if (!_mesa_validate_pbo_access(&ctx->DefaultPacking, mapsize, 1, 1,
+                                     GL_INTENSITY, GL_UNSIGNED_INT, values)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetPixelMapuiv(invalid PBO access)");
+         return;
+      }
+      /* restore */
+      ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj;
+      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
+                                              GL_WRITE_ONLY_ARB,
+                                              ctx->Pack.BufferObj);
+      if (!buf) {
+         /* buffer is already mapped - that's an error */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetPixelMapuiv(PBO is mapped)");
+         return;
+      }
+      values = (GLuint *) ADD_POINTERS(buf, values);
+   }
+   else if (!values) {
+      return;
+   }
+
    switch (map) {
       case GL_PIXEL_MAP_I_TO_I:
-         MEMCPY(values, ctx->Pixel.MapItoI, ctx->Pixel.MapItoIsize*sizeof(GLint));
+         MEMCPY(values, ctx->Pixel.MapItoI, mapsize * sizeof(GLint));
         break;
       case GL_PIXEL_MAP_S_TO_S:
-         MEMCPY(values, ctx->Pixel.MapStoS, ctx->Pixel.MapStoSsize*sizeof(GLint));
+         MEMCPY(values, ctx->Pixel.MapStoS, mapsize * sizeof(GLint));
         break;
       case GL_PIXEL_MAP_I_TO_R:
-        for (i=0;i<ctx->Pixel.MapItoRsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapItoR[i] );
         }
         break;
       case GL_PIXEL_MAP_I_TO_G:
-        for (i=0;i<ctx->Pixel.MapItoGsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapItoG[i] );
         }
         break;
       case GL_PIXEL_MAP_I_TO_B:
-        for (i=0;i<ctx->Pixel.MapItoBsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapItoB[i] );
         }
         break;
       case GL_PIXEL_MAP_I_TO_A:
-        for (i=0;i<ctx->Pixel.MapItoAsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapItoA[i] );
         }
         break;
       case GL_PIXEL_MAP_R_TO_R:
-        for (i=0;i<ctx->Pixel.MapRtoRsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapRtoR[i] );
         }
         break;
       case GL_PIXEL_MAP_G_TO_G:
-        for (i=0;i<ctx->Pixel.MapGtoGsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapGtoG[i] );
         }
         break;
       case GL_PIXEL_MAP_B_TO_B:
-        for (i=0;i<ctx->Pixel.MapBtoBsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapBtoB[i] );
         }
         break;
       case GL_PIXEL_MAP_A_TO_A:
-        for (i=0;i<ctx->Pixel.MapAtoAsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_UINT( ctx->Pixel.MapAtoA[i] );
         }
         break;
       default:
          _mesa_error( ctx, GL_INVALID_ENUM, "glGetPixelMapfv" );
    }
+
+   if (ctx->Pack.BufferObj->Name) {
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
+                              ctx->Pack.BufferObj);
+   }
 }
 
 
@@ -506,63 +758,99 @@ void GLAPIENTRY
 _mesa_GetPixelMapusv( GLenum map, GLushort *values )
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLint i;
+   GLint mapsize, i;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   mapsize = get_map_size(ctx, map);
+
+   if (ctx->Pack.BufferObj->Name) {
+      /* pack pixelmap into PBO */
+      GLubyte *buf;
+      /* Note, need to use DefaultPacking and Pack's buffer object */
+      ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj;
+      if (!_mesa_validate_pbo_access(&ctx->DefaultPacking, mapsize, 1, 1,
+                                     GL_INTENSITY, GL_UNSIGNED_SHORT,
+                                     values)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetPixelMapusv(invalid PBO access)");
+         return;
+      }
+      /* restore */
+      ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj;
+      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
+                                              GL_WRITE_ONLY_ARB,
+                                              ctx->Pack.BufferObj);
+      if (!buf) {
+         /* buffer is already mapped - that's an error */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetPixelMapusv(PBO is mapped)");
+         return;
+      }
+      values = (GLushort *) ADD_POINTERS(buf, values);
+   }
+   else if (!values) {
+      return;
+   }
+
    switch (map) {
       case GL_PIXEL_MAP_I_TO_I:
-        for (i=0;i<ctx->Pixel.MapItoIsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = (GLushort) ctx->Pixel.MapItoI[i];
         }
         break;
       case GL_PIXEL_MAP_S_TO_S:
-        for (i=0;i<ctx->Pixel.MapStoSsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = (GLushort) ctx->Pixel.MapStoS[i];
         }
         break;
       case GL_PIXEL_MAP_I_TO_R:
-        for (i=0;i<ctx->Pixel.MapItoRsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapItoR[i] );
         }
         break;
       case GL_PIXEL_MAP_I_TO_G:
-        for (i=0;i<ctx->Pixel.MapItoGsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapItoG[i] );
         }
         break;
       case GL_PIXEL_MAP_I_TO_B:
-        for (i=0;i<ctx->Pixel.MapItoBsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapItoB[i] );
         }
         break;
       case GL_PIXEL_MAP_I_TO_A:
-        for (i=0;i<ctx->Pixel.MapItoAsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapItoA[i] );
         }
         break;
       case GL_PIXEL_MAP_R_TO_R:
-        for (i=0;i<ctx->Pixel.MapRtoRsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapRtoR[i] );
         }
         break;
       case GL_PIXEL_MAP_G_TO_G:
-        for (i=0;i<ctx->Pixel.MapGtoGsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapGtoG[i] );
         }
         break;
       case GL_PIXEL_MAP_B_TO_B:
-        for (i=0;i<ctx->Pixel.MapBtoBsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapBtoB[i] );
         }
         break;
       case GL_PIXEL_MAP_A_TO_A:
-        for (i=0;i<ctx->Pixel.MapAtoAsize;i++) {
+        for (i = 0; i < mapsize; i++) {
            values[i] = FLOAT_TO_USHORT( ctx->Pixel.MapAtoA[i] );
         }
         break;
       default:
          _mesa_error( ctx, GL_INVALID_ENUM, "glGetPixelMapfv" );
    }
+
+   if (ctx->Pack.BufferObj->Name) {
+      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
+                              ctx->Pack.BufferObj);
+   }
 }
 
 
@@ -776,16 +1064,17 @@ _mesa_PixelTransferi( GLenum pname, GLint param )
    _mesa_PixelTransferf( pname, (GLfloat) param );
 }
 
+
+
 /**********************************************************************/
 /*****                  Pixel processing functions               ******/
 /**********************************************************************/
 
-
 /*
  * Apply scale and bias factors to an array of RGBA pixels.
  */
 void
-_mesa_scale_and_bias_rgba(const GLcontext *ctx, GLuint n, GLfloat rgba[][4],
+_mesa_scale_and_bias_rgba(GLcontext *ctx, GLuint n, GLfloat rgba[][4],
                           GLfloat rScale, GLfloat gScale,
                           GLfloat bScale, GLfloat aScale,
                           GLfloat rBias, GLfloat gBias,