Implement glPixelStorei for Tex(Sub)Image2D.

TRAC #11475

Author:    Andrew Lewycky
Signed-off-by: Nicolas Capens
Signed-off-by: Daniel Koch

git-svn-id: https://angleproject.googlecode.com/svn/trunk@55 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/include/Context.h b/src/include/Context.h
index 1a1eec8..51a285f 100644
--- a/src/include/Context.h
+++ b/src/include/Context.h
@@ -181,6 +181,9 @@
     GLuint samplerTexture[SAMPLER_TYPE_COUNT][MAX_TEXTURE_IMAGE_UNITS];
 
     unsigned int startIndex;
+
+    GLint unpackAlignment;
+    GLint packAlignment;
 };
 
 class Context : public State
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index dc1e0a4..46a58e3 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -130,6 +130,9 @@
 
     currentProgram = 0;
 
+    packAlignment = 4;
+    unpackAlignment = 4;
+
     mBufferBackEnd = NULL;
     mVertexDataManager = NULL;
 
@@ -1741,7 +1744,7 @@
           case SAMPLER_2D:
             {
                 Texture2D *incomplete2d = new Texture2D;
-                incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
+                incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
                 t = incomplete2d;
             }
             break;
@@ -1750,12 +1753,12 @@
             {
               TextureCubeMap *incompleteCube = new TextureCubeMap;
 
-              incompleteCube->setImagePosX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
-              incompleteCube->setImageNegX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
-              incompleteCube->setImagePosY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
-              incompleteCube->setImageNegY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
-              incompleteCube->setImagePosZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
-              incompleteCube->setImageNegZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
+              incompleteCube->setImagePosX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+              incompleteCube->setImageNegX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+              incompleteCube->setImagePosY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+              incompleteCube->setImageNegY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+              incompleteCube->setImagePosZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+              incompleteCube->setImageNegZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
 
               t = incompleteCube;
             }
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 9ee9ddc..1012079 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -163,12 +163,20 @@
     return img.width * 4;
 }
 
+GLsizei Texture::computePitch(GLsizei width, GLenum format, GLenum type, GLint alignment) const
+{
+    ASSERT(alignment > 0 && isPow2(alignment));
+
+    GLsizei rawPitch = pixelSize(format, type) * width;
+    return (rawPitch + alignment - 1) & ~(alignment - 1);
+}
+
 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
 // into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
 void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
-                            const void *input, size_t outputPitch, void *output) const
+                            GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
 {
-    size_t inputPitch = width * pixelSize(format, type);
+    GLsizei inputPitch = computePitch(width, format, type, unpackAlignment);
 
     for (int y = 0; y < height; y++)
     {
@@ -277,7 +285,7 @@
     }
 }
 
-void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img)
+void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
 {
     IDirect3DSurface9 *newSurface = NULL;
     HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
@@ -304,7 +312,7 @@
 
         if (SUCCEEDED(result))
         {
-            loadImageData(0, 0, width, height, format, type, pixels, locked.Pitch, locked.pBits);
+            loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
             newSurface->UnlockRect();
         }
 
@@ -314,7 +322,7 @@
     mDirtyMetaData = true;
 }
 
-void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img)
+void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
 {
     if (width + xoffset > img->width || height + yoffset > img->height) return error(GL_INVALID_VALUE);
 
@@ -325,7 +333,7 @@
 
     if (SUCCEEDED(result))
     {
-        loadImageData(xoffset, yoffset, width, height, format, type, pixels, locked.Pitch, locked.pBits);
+        loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
         img->surface->UnlockRect();
     }
 
@@ -399,9 +407,9 @@
     return GL_TEXTURE_2D;
 }
 
-void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    Texture::setImage(width, height, format, type, pixels, &mImageArray[level]);
+    Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
 
     if (level == 0)
     {
@@ -445,9 +453,9 @@
     }
 }
 
-void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    Texture::subImage(xoffset, yoffset, width, height, format, type, pixels, &mImageArray[level]);
+    Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
     commitRect(level, xoffset, yoffset, width, height);
 }
 
@@ -665,34 +673,34 @@
     return GL_TEXTURE_CUBE_MAP;
 }
 
-void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    setImage(0, level, internalFormat, width, height, format, type, pixels);
+    setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
 }
 
-void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    setImage(1, level, internalFormat, width, height, format, type, pixels);
+    setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
 }
 
-void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    setImage(2, level, internalFormat, width, height, format, type, pixels);
+    setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
 }
 
-void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    setImage(3, level, internalFormat, width, height, format, type, pixels);
+    setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
 }
 
-void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    setImage(4, level, internalFormat, width, height, format, type, pixels);
+    setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
 }
 
-void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    setImage(5, level, internalFormat, width, height, format, type, pixels);
+    setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
 }
 
 void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
@@ -732,9 +740,9 @@
     }
 }
 
-void TextureCubeMap::subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    Texture::subImage(xoffset, yoffset, width, height, format, type, pixels, &mImageArray[faceIndex(face)][level]);
+    Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]);
     commitRect(face, level, xoffset, yoffset, width, height);
 }
 
@@ -932,9 +940,9 @@
     return surface;
 }
 
-void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
 {
-    Texture::setImage(width, height, format, type, pixels, &mImageArray[face][level]);
+    Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
 
     if (face == 0 && level == 0)
     {
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index 08aa0f3..2dd3cbe 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -79,8 +79,8 @@
     GLenum mWrapS;
     GLenum mWrapT;
 
-    void setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img);
-    void subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img);
+    void setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img);
+    void subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img);
 
     // The pointer returned is weak and it is assumed the derived class will keep a strong pointer until the next createTexture() call.
     virtual IDirect3DBaseTexture9 *createTexture() = 0;
@@ -98,7 +98,9 @@
     bool mDirtyMetaData;
 
     void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
-                       const void *input, std::size_t outputPitch, void *output) const;
+                       GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output) const;
+
+    GLsizei computePitch(GLsizei width, GLenum format, GLenum type, GLint alignment) const;
 };
 
 class Texture2D : public Texture
@@ -110,8 +112,8 @@
 
     GLenum getTarget() const;
 
-    void setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
-    void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+    void setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+    void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 
     bool isComplete() const;
 
@@ -141,14 +143,14 @@
 
     GLenum getTarget() const;
 
-    void setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
-    void setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
-    void setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
-    void setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
-    void setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
-    void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+    void setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+    void setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+    void setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+    void setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+    void setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+    void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 
-    void subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+    void subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
 
     bool isComplete() const;
 
@@ -164,7 +166,7 @@
 
     static unsigned int faceIndex(GLenum face);
 
-    void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+    void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
     void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
 
     Image mImageArray[6][MAX_TEXTURE_LEVELS];
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 444c707..26e347e 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -1795,6 +1795,8 @@
               case GL_FRAMEBUFFER_BINDING:              *params = context->framebuffer;             break;
               case GL_RENDERBUFFER_BINDING:             *params = context->renderbuffer;            break;
               case GL_CURRENT_PROGRAM:                  *params = context->currentProgram;          break;
+              case GL_PACK_ALIGNMENT:                   *params = context->packAlignment;           break;
+              case GL_UNPACK_ALIGNMENT:                 *params = context->unpackAlignment;         break;
               case GL_RED_BITS:
               case GL_GREEN_BITS:
               case GL_BLUE_BITS:
@@ -2498,16 +2500,33 @@
 
     try
     {
-        switch (pname)
+        gl::Context *context = gl::getContext();
+
+        if (context)
         {
-          case GL_UNPACK_ALIGNMENT:
-        //    UNIMPLEMENTED();   // FIXME
-            break;
-          case GL_PACK_ALIGNMENT:
-        //    UNIMPLEMENTED();   // FIXME
-            break;
-          default:
-            return error(GL_INVALID_ENUM);
+            switch (pname)
+            {
+              case GL_UNPACK_ALIGNMENT:
+                if (param != 1 && param != 2 && param != 4 && param != 8)
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+
+                context->unpackAlignment = param;
+                break;
+
+              case GL_PACK_ALIGNMENT:
+                if (param != 1 && param != 2 && param != 4 && param != 8)
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+
+                context->packAlignment = param;
+                break;
+
+              default:
+                return error(GL_INVALID_ENUM);
+            }
         }
     }
     catch(std::bad_alloc&)
@@ -3057,7 +3076,7 @@
                     return error(GL_INVALID_OPERATION);
                 }
 
-                texture->setImage(level, internalformat, width, height, format, type, pixels);
+                texture->setImage(level, internalformat, width, height, format, type, context->unpackAlignment, pixels);
             }
             else
             {
@@ -3071,22 +3090,22 @@
                 switch (target)
                 {
                   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-                    texture->setImagePosX(level, internalformat, width, height, format, type, pixels);
+                    texture->setImagePosX(level, internalformat, width, height, format, type, context->unpackAlignment, pixels);
                     break;
                   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-                    texture->setImageNegX(level, internalformat, width, height, format, type, pixels);
+                    texture->setImageNegX(level, internalformat, width, height, format, type, context->unpackAlignment, pixels);
                     break;
                   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-                    texture->setImagePosY(level, internalformat, width, height, format, type, pixels);
+                    texture->setImagePosY(level, internalformat, width, height, format, type, context->unpackAlignment, pixels);
                     break;
                   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-                    texture->setImageNegY(level, internalformat, width, height, format, type, pixels);
+                    texture->setImageNegY(level, internalformat, width, height, format, type, context->unpackAlignment, pixels);
                     break;
                   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-                    texture->setImagePosZ(level, internalformat, width, height, format, type, pixels);
+                    texture->setImagePosZ(level, internalformat, width, height, format, type, context->unpackAlignment, pixels);
                     break;
                   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-                    texture->setImageNegZ(level, internalformat, width, height, format, type, pixels);
+                    texture->setImageNegZ(level, internalformat, width, height, format, type, context->unpackAlignment, pixels);
                     break;
                   default: UNREACHABLE();
                 }
@@ -3220,7 +3239,7 @@
                     return error(GL_INVALID_OPERATION);
                 }
 
-                texture->subImage(level, xoffset, yoffset, width, height, format, type, pixels);
+                texture->subImage(level, xoffset, yoffset, width, height, format, type, context->unpackAlignment, pixels);
             }
             else if (es2dx::IsCubemapTextureTarget(target))
             {
@@ -3231,7 +3250,7 @@
                     return error(GL_INVALID_OPERATION);
                 }
 
-                texture->subImage(target, level, xoffset, yoffset, width, height, format, type, pixels);
+                texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->unpackAlignment, pixels);
             }
             else
             {