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/Context.cpp b/src/libGLESv2/Context.cpp
index 6789c7f..10213da 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -214,12 +214,28 @@
 {
     IDirect3DDevice9 *device = display->getDevice();
 
-    if (!mBufferBackEnd)
+    if (!mHasBeenCurrent)
     {
+        device->GetDeviceCaps(&mDeviceCaps);
+
         mBufferBackEnd = new Dx9BackEnd(device);
         mVertexDataManager = new VertexDataManager(this, mBufferBackEnd);
         mIndexDataManager = new IndexDataManager(this, mBufferBackEnd);
         mBlit = new Blit(this);
+
+        initExtensionString();
+
+        mState.viewportX = 0;
+        mState.viewportY = 0;
+        mState.viewportWidth = surface->getWidth();
+        mState.viewportHeight = surface->getHeight();
+
+        mState.scissorX = 0;
+        mState.scissorY = 0;
+        mState.scissorWidth = surface->getWidth();
+        mState.scissorHeight = surface->getHeight();
+
+        mHasBeenCurrent = true;
     }
 
     // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names
@@ -240,23 +256,6 @@
     framebufferZero->setDepthbuffer(GL_RENDERBUFFER, 0);
     framebufferZero->setStencilbuffer(GL_RENDERBUFFER, 0);
 
-    if (!mHasBeenCurrent)
-    {
-        initExtensionString();
-
-        mState.viewportX = 0;
-        mState.viewportY = 0;
-        mState.viewportWidth = surface->getWidth();
-        mState.viewportHeight = surface->getHeight();
-
-        mState.scissorX = 0;
-        mState.scissorY = 0;
-        mState.scissorWidth = surface->getWidth();
-        mState.scissorHeight = surface->getHeight();
-
-        mHasBeenCurrent = true;
-    }
-
     defaultRenderTarget->Release();
 
     if (depthStencil)
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index e5bca53..9042306 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -379,6 +379,8 @@
 
     Blit *getBlitter() { return mBlit; }
 
+    const D3DCAPS9 &getDeviceCaps() { return mDeviceCaps; }
+
   private:
     DISALLOW_COPY_AND_ASSIGN(Context);
 
@@ -464,6 +466,8 @@
     bool mSampleStateDirty;
     bool mFrontFaceDirty;
     bool mDitherStateDirty;
+
+    D3DCAPS9 mDeviceCaps;
 };
 }
 
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
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index cd47e89..d9bb053 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -111,6 +111,9 @@
 
     void needRenderTarget();
 
+    GLint creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const;
+    GLint creationLevels(GLsizei size, GLint maxlevel) const;
+
     // 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;
     virtual void updateTexture() = 0;
@@ -127,6 +130,8 @@
     unsigned int mWidth;
     unsigned int mHeight;
 
+    int levelCount() const;
+
   private:
     DISALLOW_COPY_AND_ASSIGN(Texture);