Add proper detection for maximum texture and renderbuffer size
Trac #13849

Increased the maximum possible texture & renderbuffer size to 16384 (the minimum required for DX11 cards).
Limit the actual maximum texture & renderbuffer size to the maximum
that it reported by the underlying D3D9 device.

Note that creating textures and renderbuffers at the maximum size will quickly exhaust video memory!

Signed-off-by: Nicolas Capens

git-svn-id: https://angleproject.googlecode.com/svn/trunk@447 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 55cdae3..f50aa4d 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -240,6 +240,16 @@
         mIndexDataManager = new IndexDataManager(this, mBufferBackEnd);
         mBlit = new Blit(this);
 
+        mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0);
+
+        mMaxTextureDimension = std::min(std::min((int)mDeviceCaps.MaxTextureWidth, (int)mDeviceCaps.MaxTextureHeight),
+                                        (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE);
+        mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE);
+        mMaxRenderbufferDimension = mMaxTextureDimension;
+        mMaxTextureLevel = log2(mMaxTextureDimension) + 1;
+        TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d",
+              mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel);
+
         const D3DFORMAT renderBufferFormats[] =
         {
             D3DFMT_A8R8G8B8,
@@ -306,8 +316,6 @@
         depthStencil->Release();
     }
     
-    mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0);
-
     markAllStateDirty();
 }
 
@@ -1202,7 +1210,7 @@
       case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:   *params = gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS;   break;
       case GL_MAX_TEXTURE_IMAGE_UNITS:          *params = gl::MAX_TEXTURE_IMAGE_UNITS;          break;
       case GL_MAX_FRAGMENT_UNIFORM_VECTORS:     *params = gl::MAX_FRAGMENT_UNIFORM_VECTORS;     break;
-      case GL_MAX_RENDERBUFFER_SIZE:            *params = gl::MAX_RENDERBUFFER_SIZE;            break;
+      case GL_MAX_RENDERBUFFER_SIZE:            *params = getMaximumRenderbufferDimension();    break;
       case GL_NUM_SHADER_BINARY_FORMATS:        *params = 0;                                    break;
       case GL_SHADER_BINARY_FORMATS:      /* no shader binary formats are supported */          break;
       case GL_ARRAY_BUFFER_BINDING:             *params = mState.arrayBuffer.id();              break;
@@ -1240,8 +1248,8 @@
       case GL_STENCIL_BACK_WRITEMASK:           *params = mState.stencilBackWritemask;          break;
       case GL_STENCIL_CLEAR_VALUE:              *params = mState.stencilClearValue;             break;
       case GL_SUBPIXEL_BITS:                    *params = 4;                                    break;
-      case GL_MAX_TEXTURE_SIZE:                 *params = gl::MAX_TEXTURE_SIZE;                 break;
-      case GL_MAX_CUBE_MAP_TEXTURE_SIZE:        *params = gl::MAX_CUBE_MAP_TEXTURE_SIZE;        break;
+      case GL_MAX_TEXTURE_SIZE:                 *params = getMaximumTextureDimension();         break;
+      case GL_MAX_CUBE_MAP_TEXTURE_SIZE:        *params = getMaximumCubeTextureDimension();     break;
       case GL_NUM_COMPRESSED_TEXTURE_FORMATS:   
         {
             if (supportsCompressedTextures())
@@ -1303,7 +1311,7 @@
       case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = gl::IMPLEMENTATION_COLOR_READ_FORMAT; break;
       case GL_MAX_VIEWPORT_DIMS:
         {
-            int maxDimension = std::max((int)gl::MAX_RENDERBUFFER_SIZE, (int)gl::MAX_TEXTURE_SIZE);
+            int maxDimension = std::max(getMaximumRenderbufferDimension(), getMaximumTextureDimension());
             params[0] = maxDimension;
             params[1] = maxDimension;
         }
@@ -2954,6 +2962,26 @@
     return mSupportsHalfFloatRenderableTextures;
 }
 
+int Context::getMaximumRenderbufferDimension() const
+{
+    return mMaxRenderbufferDimension;
+}
+
+int Context::getMaximumTextureDimension() const
+{
+    return mMaxTextureDimension;
+}
+
+int Context::getMaximumCubeTextureDimension() const
+{
+    return mMaxCubeTextureDimension;
+}
+
+int Context::getMaximumTextureLevel() const
+{
+    return mMaxTextureLevel;
+}
+
 void Context::detachBuffer(GLuint buffer)
 {
     // [OpenGL ES 2.0.24] section 2.9 page 22:
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index 8ecebcb..2452dd4 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -63,7 +63,6 @@
     MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0,
     MAX_TEXTURE_IMAGE_UNITS = 16,
     MAX_FRAGMENT_UNIFORM_VECTORS = 16,
-    MAX_RENDERBUFFER_SIZE = 4096,   // FIXME: Verify
     MAX_DRAW_BUFFERS = 1,
 
     IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB,
@@ -383,6 +382,10 @@
     GLenum getError();
 
     bool supportsShaderModel3() const;
+    int getMaximumRenderbufferDimension() const;
+    int getMaximumTextureDimension() const;
+    int getMaximumCubeTextureDimension() const;
+    int getMaximumTextureLevel() const;
     GLsizei getMaxSupportedSamples() const;
     int getNearestSupportedSamples(D3DFORMAT format, int requested) const;
     const char *getExtensionString() const;
@@ -459,6 +462,10 @@
     bool mDepthStencilInitialized;
 
     bool mSupportsShaderModel3;
+    int  mMaxRenderbufferDimension;
+    int  mMaxTextureDimension;
+    int  mMaxCubeTextureDimension;
+    int  mMaxTextureLevel;
     std::map<D3DFORMAT, bool *> mMultiSampleSupport;
     GLsizei mMaxSupportedSamples;
     bool mSupportsEventQueries;
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 05632c4..9128f13 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -996,7 +996,7 @@
 
         // Purge all the levels and the texture.
 
-        for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
+        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
         {
             if (mImageArray[i].surface != NULL)
             {
@@ -1831,7 +1831,7 @@
               internalFormat, width);
 
         // Purge all the levels and the texture.
-        for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
+        for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
         {
             for (int f = 0; f < 6; f++)
             {
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index 6285a7c..5cf3214 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -28,10 +28,13 @@
 
 enum
 {
-    MAX_TEXTURE_SIZE = 2048,
-    MAX_CUBE_MAP_TEXTURE_SIZE = 2048,
+    // These are the maximums the implementation can support
+    // The actual GL caps are limited by the device caps
+    // and should be queried from the Context
+    IMPLEMENTATION_MAX_TEXTURE_SIZE = 16384,
+    IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384,
 
-    MAX_TEXTURE_LEVELS = 12   // 1+log2 of MAX_TEXTURE_SIZE
+    IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15   // 1+log2 of MAX_TEXTURE_SIZE
 };
 
 class Texture : public RefCountObject
@@ -237,7 +240,7 @@
     bool redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type);
     void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
 
-    Image mImageArray[MAX_TEXTURE_LEVELS];
+    Image mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
 
     IDirect3DTexture9 *mTexture;
 
@@ -297,7 +300,7 @@
     void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
     bool redefineTexture(GLint level, GLenum internalFormat, GLsizei width);
 
-    Image mImageArray[6][MAX_TEXTURE_LEVELS];
+    Image mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS];
 
     IDirect3DCubeTexture9 *mTexture;
 
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 7ac312d..c986b5e 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -737,7 +737,7 @@
 
     try
     {
-        if (level < 0 || level > gl::MAX_TEXTURE_LEVELS)
+        if (level < 0)
         {
             return error(GL_INVALID_VALUE);
         }
@@ -747,34 +747,6 @@
             return error(GL_INVALID_VALUE);
         }
 
-        switch (target)
-        {
-          case GL_TEXTURE_2D:
-            if (width > (gl::MAX_TEXTURE_SIZE >> level) || height > (gl::MAX_TEXTURE_SIZE >> level))
-            {
-                return error(GL_INVALID_VALUE);
-            }
-            break;
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-            if (width != height)
-            {
-                return error(GL_INVALID_VALUE);
-            }
-
-            if (width > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level) || height > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level))
-            {
-                return error(GL_INVALID_VALUE);
-            }
-            break;
-          default:
-            return error(GL_INVALID_ENUM);
-        }
-
         switch (internalformat)
         {
           case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
@@ -793,6 +765,41 @@
 
         if (context)
         {
+            if (level > context->getMaximumTextureLevel())
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
+            switch (target)
+            {
+              case GL_TEXTURE_2D:
+                if (width > (context->getMaximumTextureDimension() >> level) ||
+                    height > (context->getMaximumTextureDimension() >> level))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+                if (width != height)
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+
+                if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+                    height > (context->getMaximumCubeTextureDimension() >> level))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
+              default:
+                return error(GL_INVALID_ENUM);
+            }
+
             if (!context->supportsCompressedTextures())
             {
                 return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
@@ -860,7 +867,7 @@
             return error(GL_INVALID_ENUM);
         }
 
-        if (level < 0 || level > gl::MAX_TEXTURE_LEVELS)
+        if (level < 0)
         {
             return error(GL_INVALID_VALUE);
         }
@@ -889,6 +896,11 @@
 
         if (context)
         {
+            if (level > context->getMaximumTextureLevel())
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
             if (!context->supportsCompressedTextures())
             {
                 return error(GL_INVALID_ENUM); // in this case, it's as though the format switch has failed.
@@ -979,34 +991,6 @@
             return error(GL_INVALID_VALUE);
         }
 
-        switch (target)
-        {
-          case GL_TEXTURE_2D:
-            if (width > (gl::MAX_TEXTURE_SIZE >> level) || height > (gl::MAX_TEXTURE_SIZE >> level))
-            {
-                return error(GL_INVALID_VALUE);
-            }
-            break;
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-            if (width != height)
-            {
-                return error(GL_INVALID_VALUE);
-            }
-
-            if (width > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level) || height > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level))
-            {
-                return error(GL_INVALID_VALUE);
-            }
-            break;
-          default:
-            return error(GL_INVALID_ENUM);
-        }
-
         switch (internalformat)
         {
           case GL_ALPHA:
@@ -1030,6 +1014,36 @@
 
         if (context)
         {
+            switch (target)
+            {
+              case GL_TEXTURE_2D:
+                if (width > (context->getMaximumTextureDimension() >> level) ||
+                    height > (context->getMaximumTextureDimension() >> level))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+                if (width != height)
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+
+                if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+                    height > (context->getMaximumCubeTextureDimension() >> level))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
+              default:
+                return error(GL_INVALID_ENUM);
+            }
+
             if (internalformat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || 
                 internalformat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
             {
@@ -1122,7 +1136,7 @@
             return error(GL_INVALID_ENUM);
         }
 
-        if (level < 0 || level > gl::MAX_TEXTURE_LEVELS || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+        if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
         {
             return error(GL_INVALID_VALUE);
         }
@@ -1141,6 +1155,11 @@
 
         if (context)
         {
+            if (level > context->getMaximumTextureLevel())
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
             gl::Framebuffer *framebuffer = context->getReadFramebuffer();
             if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
             {
@@ -4011,7 +4030,7 @@
             return error(GL_INVALID_ENUM);
         }
 
-        if (width < 0 || height < 0 || width > gl::MAX_RENDERBUFFER_SIZE || height > gl::MAX_RENDERBUFFER_SIZE || samples < 0)
+        if (width < 0 || height < 0 || samples < 0)
         {
             return error(GL_INVALID_VALUE);
         }
@@ -4020,7 +4039,9 @@
 
         if (context)
         {
-            if (samples > context->getMaxSupportedSamples())
+            if (width > context->getMaximumRenderbufferDimension() || 
+                height > context->getMaximumRenderbufferDimension() ||
+                samples > context->getMaxSupportedSamples())
             {
                 return error(GL_INVALID_VALUE);
             }
@@ -4429,34 +4450,6 @@
             return error(GL_INVALID_VALUE);
         }
 
-        switch (target)
-        {
-          case GL_TEXTURE_2D:
-            if (width > (gl::MAX_TEXTURE_SIZE >> level) || height > (gl::MAX_TEXTURE_SIZE >> level))
-            {
-                return error(GL_INVALID_VALUE);
-            }
-            break;
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-            if (width != height)
-            {
-                return error(GL_INVALID_VALUE);
-            }
-
-            if (width > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level) || height > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level))
-            {
-                return error(GL_INVALID_VALUE);
-            }
-            break;
-          default:
-            return error(GL_INVALID_ENUM);
-        }
-
         if (internalformat != format)
         {
             return error(GL_INVALID_OPERATION);
@@ -4527,6 +4520,36 @@
 
         if (context)
         {
+            switch (target)
+            {
+              case GL_TEXTURE_2D:
+                if (width > (context->getMaximumTextureDimension() >> level) ||
+                    height > (context->getMaximumTextureDimension() >> level))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+                if (width != height)
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+
+                if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+                    height > (context->getMaximumCubeTextureDimension() >> level))
+                {
+                    return error(GL_INVALID_VALUE);
+                }
+                break;
+              default:
+                return error(GL_INVALID_ENUM);
+            }
+
             if (internalformat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
                 internalformat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
             {
@@ -4697,7 +4720,7 @@
             return error(GL_INVALID_ENUM);
         }
 
-        if (level < 0 || level > gl::MAX_TEXTURE_LEVELS || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+        if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
         {
             return error(GL_INVALID_VALUE);
         }
@@ -4721,6 +4744,11 @@
 
         if (context)
         {
+            if (level > context->getMaximumTextureLevel())
+            {
+                return error(GL_INVALID_VALUE);
+            }
+
             if (format == GL_FLOAT)
             {
                 if (!context->supportsFloatTextures())