When NONPOW2CONDITIONAL is set, limit NPOTs to a single level.

TRAC #12250

Signed-off-by: Nicolas Capens
Signed-off-by: Daniel Koch

Author:    Andrew Lewycky

git-svn-id: https://angleproject.googlecode.com/svn/trunk@283 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 5d6d8eb..98d47ca 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -418,6 +418,29 @@
 }
 
 
+GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
+{
+    if (isPow2(width) && isPow2(height))
+    {
+        return maxlevel;
+    }
+    else
+    {
+        // One of the restrictions of NONPOW2CONDITIONAL is that NPOTs may only have a single level.
+        return (getContext()->getDeviceCaps().TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) ? 1 : maxlevel;
+    }
+}
+
+GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
+{
+    return creationLevels(size, size, maxlevel);
+}
+
+int Texture::levelCount() const
+{
+    return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
+}
+
 Texture2D::Texture2D(Context *context) : Texture(context)
 {
     mTexture = NULL;
@@ -502,7 +525,7 @@
 {
     ASSERT(mImageArray[level].surface != NULL);
 
-    if (mTexture != NULL)
+    if (level < levelCount())
     {
         IDirect3DSurface9 *destLevel = NULL;
         HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
@@ -547,7 +570,7 @@
         pushTexture(mTexture, true);
     }
 
-    if (width != 0 && height != 0)
+    if (width != 0 && height != 0 && level < levelCount())
     {
         RECT sourceRect;
         sourceRect.left = x;
@@ -584,17 +607,20 @@
         needRenderTarget();
     }
 
-    RECT sourceRect;
-    sourceRect.left = x;
-    sourceRect.right = x + width;
-    sourceRect.top = y;
-    sourceRect.bottom = y + height;
+    if (level < levelCount())
+    {
+        RECT sourceRect;
+        sourceRect.left = x;
+        sourceRect.right = x + width;
+        sourceRect.top = y;
+        sourceRect.bottom = y + height;
 
-    IDirect3DSurface9 *dest;
-    HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
+        IDirect3DSurface9 *dest;
+        HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
 
-    getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
-    dest->Release();
+        getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
+        dest->Release();
+    }
 }
 
 // Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
@@ -665,7 +691,7 @@
     IDirect3DDevice9 *device = getDevice();
     D3DFORMAT format = selectFormat(mImageArray[0].format);
 
-    HRESULT result = device->CreateTexture(mWidth, mHeight, 0, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
+    HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
 
     if (FAILED(result))
     {
@@ -682,9 +708,9 @@
 {
     IDirect3DDevice9 *device = getDevice();
 
-    int levelCount = mTexture->GetLevelCount();
+    int levels = levelCount();
 
-    for (int level = 0; level < levelCount; level++)
+    for (int level = 0; level < levels; level++)
     {
         if (mImageArray[level].dirty)
         {
@@ -716,7 +742,7 @@
         IDirect3DDevice9 *device = getDevice();
         D3DFORMAT format = selectFormat(mImageArray[0].format);
 
-        HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
+        HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
 
         if (FAILED(result))
         {
@@ -726,7 +752,7 @@
 
         if (mTexture != NULL)
         {
-            int levels = texture->GetLevelCount();
+            int levels = levelCount();
             for (int i = 0; i < levels; i++)
             {
                 IDirect3DSurface9 *source;
@@ -931,7 +957,7 @@
 
     ASSERT(mImageArray[face][level].surface != NULL);
 
-    if (mTexture != NULL)
+    if (level < levelCount())
     {
         IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
         ASSERT(destLevel != NULL);
@@ -1040,7 +1066,7 @@
 
     IDirect3DCubeTexture9 *texture;
 
-    HRESULT result = device->CreateCubeTexture(mWidth, 0, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
+    HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
 
     if (FAILED(result))
     {
@@ -1060,7 +1086,8 @@
 
     for (int face = 0; face < 6; face++)
     {
-        for (int level = 0; level <= log2(mWidth); level++)
+        int levels = levelCount();
+        for (int level = 0; level < levels; level++)
         {
             Image *img = &mImageArray[face][level];
 
@@ -1093,7 +1120,7 @@
         IDirect3DDevice9 *device = getDevice();
         D3DFORMAT format = selectFormat(mImageArray[0][0].format);
 
-        HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
+        HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
 
         if (FAILED(result))
         {
@@ -1103,7 +1130,7 @@
 
         if (mTexture != NULL)
         {
-            int levels = texture->GetLevelCount();
+            int levels = levelCount();
             for (int f = 0; f < 6; f++)
             {
                 for (int i = 0; i < levels; i++)
@@ -1257,7 +1284,7 @@
 
     ASSERT(width == height);
 
-    if (width > 0)
+    if (width > 0 && level < levelCount())
     {
         RECT sourceRect;
         sourceRect.left = x;
@@ -1326,16 +1353,19 @@
         getRenderTarget(face);
     }
 
-    RECT sourceRect;
-    sourceRect.left = x;
-    sourceRect.right = x + width;
-    sourceRect.top = y;
-    sourceRect.bottom = y + height;
+    if (level < levelCount())
+    {
+        RECT sourceRect;
+        sourceRect.left = x;
+        sourceRect.right = x + width;
+        sourceRect.top = y;
+        sourceRect.bottom = y + height;
 
-    IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
+        IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
 
-    getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
-    dest->Release();
+        getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
+        dest->Release();
+    }
 }
 
 bool TextureCubeMap::isCubeComplete() const