Implements generateMipmap for CPU-side textures

TRAC #22350

Author: Shannon Woods
Signed-off-by: Jamie Madill
Signed-off-by: Daniel Koch

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1763 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Image11.cpp b/src/libGLESv2/renderer/Image11.cpp
index 92e186c..a8a703b 100644
--- a/src/libGLESv2/renderer/Image11.cpp
+++ b/src/libGLESv2/renderer/Image11.cpp
@@ -15,6 +15,7 @@
 #include "libGLESv2/main.h"
 #include "libGLESv2/mathutil.h"
 #include "libGLESv2/renderer/renderer11_utils.h"
+#include "libGLESv2/renderer/generatemip.h"
 
 namespace rx
 {
@@ -40,6 +41,69 @@
     return static_cast<rx::Image11*>(img);
 }
 
+void Image11::generateMipmap(Image11 *dest, Image11 *src)
+{
+    ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
+    ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
+    ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
+
+    D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped;
+    dest->map(&destMapped);
+    src->map(&srcMapped);
+
+    const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
+    unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
+
+    if (sourceData && destData)
+    {
+        switch (src->getDXGIFormat())
+        {
+          case DXGI_FORMAT_R8G8B8A8_UNORM:
+          case DXGI_FORMAT_B8G8R8A8_UNORM:
+            GenerateMip<R8G8B8A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_A8_UNORM:
+            GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R8_UNORM:
+            GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R32G32B32A32_FLOAT:
+            GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R32G32B32_FLOAT:
+            GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R16G16B16A16_FLOAT:
+            GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R8G8_UNORM:
+            GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R16_FLOAT:
+            GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R16G16_FLOAT:
+            GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R32_FLOAT:
+            GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          case DXGI_FORMAT_R32G32_FLOAT:
+            GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+            break;
+          default:
+            UNREACHABLE();
+            break;
+        }
+
+        dest->unmap();
+        src->unmap();
+    }
+
+    dest->markDirty();
+}
+
 bool Image11::isDirty() const
 {
     return (mStagingTexture && mDirty);
diff --git a/src/libGLESv2/renderer/Image11.h b/src/libGLESv2/renderer/Image11.h
index 159df5b..7693aa5 100644
--- a/src/libGLESv2/renderer/Image11.h
+++ b/src/libGLESv2/renderer/Image11.h
@@ -36,6 +36,8 @@
 
     static Image11 *makeImage11(Image *img);
 
+    static void generateMipmap(Image11 *dest, Image11 *src);
+
     virtual bool isDirty() const;
     ID3D11Texture2D *getStagingTexture();
 
@@ -54,15 +56,16 @@
 
     virtual void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
 
+  protected:
+    HRESULT map(D3D11_MAPPED_SUBRESOURCE *map);
+    void unmap();
+
   private:
     DISALLOW_COPY_AND_ASSIGN(Image11);
 
     void createStagingTexture();
     bool updateStagingTexture(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
 
-    HRESULT map(D3D11_MAPPED_SUBRESOURCE *map);
-    void unmap();
-
     Renderer11 *mRenderer;
 
     DXGI_FORMAT mDXGIFormat;
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index 1d0731a..c43ce6e 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -2414,9 +2414,9 @@
 
 void Renderer11::generateMipmap(Image *dest, Image *src)
 {
-    // TODO
-    UNIMPLEMENTED();
-    return;
+    Image11 *dest11 = Image11::makeImage11(dest);
+    Image11 *src11 = Image11::makeImage11(src);
+    Image11::generateMipmap(dest11, src11);
 }
 
 TextureStorage *Renderer11::createTextureStorage2D(SwapChain *swapChain)
diff --git a/src/libGLESv2/renderer/generatemip.h b/src/libGLESv2/renderer/generatemip.h
index 988adc0..8e19736 100644
--- a/src/libGLESv2/renderer/generatemip.h
+++ b/src/libGLESv2/renderer/generatemip.h
@@ -24,6 +24,9 @@
     }
 };
 
+typedef L8 R8; // R8 type is functionally equivalent for mip purposes
+typedef L8 A8; // A8 type is functionally equivalent for mip purposes
+
 struct A8L8
 {
     unsigned char L;
@@ -35,6 +38,8 @@
     }
 };
 
+typedef A8L8 R8G8; // R8G8 type is functionally equivalent for mip purposes
+
 struct A8R8G8B8
 {
     unsigned char B;
@@ -48,6 +53,8 @@
     }
 };
 
+typedef A8R8G8B8 R8G8B8A8; // R8G8B8A8 type is functionally equivalent for mip purposes
+
 struct A16B16G16R16F
 {
     unsigned short R;
@@ -64,6 +71,28 @@
     }
 };
 
+struct R16F
+{
+    unsigned short R;
+
+    static void average(R16F *dst, const R16F *src1, const R16F *src2)
+    {
+        dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f);
+    }
+};
+
+struct R16G16F
+{
+    unsigned short R;
+    unsigned short G;
+
+    static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2)
+    {
+        dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f);
+        dst->G = gl::float32ToFloat16((gl::float16ToFloat32(src1->G) + gl::float16ToFloat32(src2->G)) * 0.5f);
+    }
+};
+
 struct A32B32G32R32F
 {
     float R;
@@ -80,6 +109,42 @@
     }
 };
 
+struct R32F
+{
+    float R;
+
+    static void average(R32F *dst, const R32F *src1, const R32F *src2)
+    {
+        dst->R = (src1->R + src2->R) * 0.5f;
+    }
+};
+
+struct R32G32F
+{
+    float R;
+    float G;
+
+    static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2)
+    {
+        dst->R = (src1->R + src2->R) * 0.5f;
+        dst->G = (src1->G + src2->G) * 0.5f;
+    }
+};
+
+struct R32G32B32F
+{
+    float R;
+    float G;
+    float B;
+
+    static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2)
+    {
+        dst->R = (src1->R + src2->R) * 0.5f;
+        dst->G = (src1->G + src2->G) * 0.5f;
+        dst->B = (src1->B + src2->B) * 0.5f;
+    }
+};
+
 template <typename T>
 static void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight,
                         const unsigned char *sourceData, int sourcePitch,