Modify texture storage classes to store a base and max level, instead of a range of levels.

TRAC #23978

Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index d1bc214..016e6e3 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -331,7 +331,7 @@
 
 int Texture::immutableLevelCount()
 {
-    return (mImmutable ? getNativeTexture()->getStorageInstance()->levelCount() : 0);
+    return (mImmutable ? getNativeTexture()->getStorageInstance()->getMaxLevel() : 0);
 }
 
 GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
@@ -436,7 +436,7 @@
 
     if (mTexStorage)
     {
-        const int storageLevels = mTexStorage->levelCount();
+        const int storageLevels = mTexStorage->getMaxLevel();
         
         if ((level >= storageLevels && storageLevels != 0) ||
             width != storageWidth ||
@@ -659,7 +659,7 @@
 
     mImmutable = true;
 
-    setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height));
+    setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height));
 }
 
 void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
@@ -669,7 +669,7 @@
 
     if (mTexStorage && mTexStorage->isManaged())
     {
-        for (int level = 0; level < mTexStorage->levelCount(); level++)
+        for (int level = 0; level < mTexStorage->getMaxLevel(); level++)
         {
             mImageArray[level]->setManagedSurface(mTexStorage, level);
         }
@@ -845,16 +845,14 @@
     ASSERT(width > 0 && height > 0);
 
     // use existing storage level count, when previously specified by TexStorage*D
-    GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height));
+    GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height));
 
-    return new rx::TextureStorageInterface2D(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height);
+    return new rx::TextureStorageInterface2D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height);
 }
 
 void Texture2D::updateStorage()
 {
-    int storageLevels = levelCount();
-
-    for (int level = 0; level < storageLevels; level++)
+    for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
     {
         if (isLevelComplete(level))
         {
@@ -994,7 +992,7 @@
 
 bool Texture2D::isValidLevel(int level) const
 {
-    return (mTexStorage ? (level < mTexStorage->levelCount()) : false);
+    return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : false);
 }
 
 TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
@@ -1299,9 +1297,9 @@
     ASSERT(size > 0);
 
     // use existing storage level count, when previously specified by TexStorage*D
-    GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(size));
+    GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(size));
 
-    return new rx::TextureStorageInterfaceCube(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, size);
+    return new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, size);
 }
 
 void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
@@ -1311,9 +1309,11 @@
 
     if (mTexStorage && mTexStorage->isManaged())
     {
+        int levels = mTexStorage->getMaxLevel();
+
         for (int faceIndex = 0; faceIndex < 6; faceIndex++)
         {
-            for (int level = 0; level < mTexStorage->levelCount(); level++)
+            for (int level = 0; level < mTexStorage->getMaxLevel(); level++)
             {
                 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
             }
@@ -1325,11 +1325,9 @@
 
 void TextureCubeMap::updateStorage()
 {
-    int storageLevels = levelCount();
-
     for (int face = 0; face < 6; face++)
     {
-        for (int level = 0; level < storageLevels; level++)
+        for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
         {
             if (isFaceLevelComplete(face, level))
             {
@@ -1407,7 +1405,7 @@
 
     if (mTexStorage)
     {
-        const int storageLevels = mTexStorage->levelCount();
+        const int storageLevels = mTexStorage->getMaxLevel();
         
         if ((level >= storageLevels && storageLevels != 0) ||
             width != storageWidth ||
@@ -1527,7 +1525,7 @@
 
     mImmutable = true;
 
-    setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), size));
+    setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), size));
 }
 
 void TextureCubeMap::generateMipmaps()
@@ -1647,7 +1645,7 @@
 
 bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
 {
-    return (mTexStorage ? (level < mTexStorage->levelCount()) : 0);
+    return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
 }
 
 Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
@@ -1795,7 +1793,7 @@
 
     mImmutable = true;
 
-    setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
+    setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
 }
 
 void Texture3D::generateMipmaps()
@@ -1987,7 +1985,7 @@
 
 bool Texture3D::isValidLevel(int level) const
 {
-    return (mTexStorage ? (level < mTexStorage->levelCount()) : 0);
+    return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
 }
 
 void Texture3D::initializeStorage(bool renderTarget)
@@ -2022,9 +2020,9 @@
     ASSERT(width > 0 && height > 0 && depth > 0);
 
     // use existing storage level count, when previously specified by TexStorage*D
-    GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height, depth));
+    GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height, depth));
 
-    return new rx::TextureStorageInterface3D(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
+    return new rx::TextureStorageInterface3D(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
 }
 
 void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
@@ -2039,9 +2037,7 @@
 
 void Texture3D::updateStorage()
 {
-    int storageLevels = levelCount();
-
-    for (int level = 0; level < storageLevels; level++)
+    for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
     {
         if (isLevelComplete(level))
         {
@@ -2154,7 +2150,7 @@
 
     if (mTexStorage)
     {
-        const int storageLevels = mTexStorage->levelCount();
+        const int storageLevels = mTexStorage->getMaxLevel();
 
         if ((level >= storageLevels && storageLevels != 0) ||
             width != storageWidth ||
@@ -2346,7 +2342,7 @@
     }
 
     mImmutable = true;
-    setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
+    setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, internalformat, IsRenderTargetUsage(mUsage), width, height, depth));
 }
 
 void Texture2DArray::generateMipmaps()
@@ -2543,7 +2539,7 @@
 
 bool Texture2DArray::isValidLevel(int level) const
 {
-    return (mTexStorage ? (level < mTexStorage->levelCount()) : 0);
+    return (mTexStorage ? (level >= mTexStorage->getBaseLevel() && level < mTexStorage->getMaxLevel()) : 0);
 }
 
 void Texture2DArray::initializeStorage(bool renderTarget)
@@ -2578,9 +2574,9 @@
     ASSERT(width > 0 && height > 0 && depth > 0);
 
     // use existing storage level count, when previously specified by TexStorage*D
-    GLint levels = (mTexStorage ? mTexStorage->levelCount() : creationLevels(width, height));
+    GLint levels = (mTexStorage ? mTexStorage->getMaxLevel() : creationLevels(width, height));
 
-    return new rx::TextureStorageInterface2DArray(mRenderer, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
+    return new rx::TextureStorageInterface2DArray(mRenderer, 0, levels, getBaseLevelInternalFormat(), renderTarget, width, height, depth);
 }
 
 void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
@@ -2595,9 +2591,7 @@
 
 void Texture2DArray::updateStorage()
 {
-    int storageLevels = levelCount();
-
-    for (int level = 0; level < storageLevels; level++)
+    for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
     {
         if (isLevelComplete(level))
         {
@@ -2712,7 +2706,7 @@
 
     if (mTexStorage)
     {
-        const int storageLevels = mTexStorage->levelCount();
+        const int storageLevels = mTexStorage->getMaxLevel();
 
         if ((level >= storageLevels && storageLevels != 0) ||
             width != storageWidth ||
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index e4ead62..74ba130 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -242,10 +242,10 @@
     virtual Image *createImage() = 0;
     virtual void generateMipmap(Image *dest, Image *source) = 0;
     virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0;
-    virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height) = 0;
-    virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, bool renderTarget, int size) = 0;
-    virtual TextureStorage *createTextureStorage3D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth) = 0;
-    virtual TextureStorage *createTextureStorage2DArray(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth) = 0;
+    virtual TextureStorage *createTextureStorage2D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height) = 0;
+    virtual TextureStorage *createTextureStorageCube(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size) = 0;
+    virtual TextureStorage *createTextureStorage3D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth) = 0;
+    virtual TextureStorage *createTextureStorage2DArray(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth) = 0;
 
     // Buffer creation
     virtual VertexBuffer *createVertexBuffer() = 0;
diff --git a/src/libGLESv2/renderer/TextureStorage.cpp b/src/libGLESv2/renderer/TextureStorage.cpp
index 55f1bdc..fea4f59 100644
--- a/src/libGLESv2/renderer/TextureStorage.cpp
+++ b/src/libGLESv2/renderer/TextureStorage.cpp
@@ -57,13 +57,19 @@
     return mInstance->getLodOffset();
 }
 
-int TextureStorageInterface::levelCount()
+int TextureStorageInterface::getBaseLevel() const
 {
-    return mInstance->levelCount();
+    return mInstance->getBaseLevel();
 }
 
-static unsigned int GetActualLevelCount(GLsizei width, GLsizei height, GLsizei depth, GLint levelCount)
+int TextureStorageInterface::getMaxLevel() const
 {
+    return mInstance->getMaxLevel();
+}
+
+static unsigned int GetActualLevelCount(GLsizei width, GLsizei height, GLsizei depth, int baseLevel, int maxLevel)
+{
+    int levelCount = maxLevel - baseLevel;
     return (levelCount <= 0) ? std::max(std::max(gl::log2(width), gl::log2(height)), gl::log2(depth)) : levelCount;
 }
 
@@ -74,12 +80,12 @@
     mInstance = renderer->createTextureStorage2D(swapchain);
 }
 
-TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
+TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
 {
-    unsigned int actualLevels = GetActualLevelCount(width, height, 0, levels);
+    unsigned int actualLevels = GetActualLevelCount(width, height, 0, baseLevel, maxLevel);
     mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(actualLevels);
 
-    mInstance = renderer->createTextureStorage2D(levels, internalformat, renderTarget, width, height);
+    mInstance = renderer->createTextureStorage2D(baseLevel, maxLevel, internalformat, renderTarget, width, height);
 }
 
 TextureStorageInterface2D::~TextureStorageInterface2D()
@@ -101,12 +107,12 @@
     return mFirstRenderTargetSerial + level;
 }
 
-TextureStorageInterfaceCube::TextureStorageInterfaceCube(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, int size)
+TextureStorageInterfaceCube::TextureStorageInterfaceCube(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size)
 {
-    unsigned int actualLevels = GetActualLevelCount(size, size, 0, levels);
+    unsigned int actualLevels = GetActualLevelCount(size, size, 0, baseLevel, maxLevel);
     mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(actualLevels * 6);
 
-    mInstance = renderer->createTextureStorageCube(levels, internalformat, renderTarget, size);
+    mInstance = renderer->createTextureStorageCube(baseLevel, maxLevel, internalformat, renderTarget, size);
 }
 
 TextureStorageInterfaceCube::~TextureStorageInterfaceCube()
@@ -128,13 +134,13 @@
     return mFirstRenderTargetSerial + (level * 6) + gl::TextureCubeMap::targetToIndex(target);
 }
 
-TextureStorageInterface3D::TextureStorageInterface3D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+TextureStorageInterface3D::TextureStorageInterface3D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                                                      GLsizei width, GLsizei height, GLsizei depth)
 {
-    mLevels = GetActualLevelCount(width, height, depth, levels);
+    mLevels = GetActualLevelCount(width, height, depth, baseLevel, maxLevel);
     mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(mLevels * depth);
 
-    mInstance = renderer->createTextureStorage3D(levels, internalformat, renderTarget, width, height, depth);
+    mInstance = renderer->createTextureStorage3D(baseLevel, maxLevel, internalformat, renderTarget, width, height, depth);
 }
 
 TextureStorageInterface3D::~TextureStorageInterface3D()
@@ -161,13 +167,13 @@
     return mFirstRenderTargetSerial + (layer * mLevels) + level;
 }
 
-TextureStorageInterface2DArray::TextureStorageInterface2DArray(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+TextureStorageInterface2DArray::TextureStorageInterface2DArray(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                                                                GLsizei width, GLsizei height, GLsizei depth)
 {
-    mLevels = GetActualLevelCount(width, height, 0, levels);
+    mLevels = GetActualLevelCount(width, height, 0, baseLevel, maxLevel);
     mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(mLevels * depth);
 
-    mInstance = renderer->createTextureStorage2DArray(levels, internalformat, renderTarget, width, height, depth);
+    mInstance = renderer->createTextureStorage2DArray(baseLevel, maxLevel, internalformat, renderTarget, width, height, depth);
 }
 
 TextureStorageInterface2DArray::~TextureStorageInterface2DArray()
diff --git a/src/libGLESv2/renderer/TextureStorage.h b/src/libGLESv2/renderer/TextureStorage.h
index 1b25e67..298e429 100644
--- a/src/libGLESv2/renderer/TextureStorage.h
+++ b/src/libGLESv2/renderer/TextureStorage.h
@@ -28,7 +28,8 @@
     virtual int getLodOffset() const = 0;
     virtual bool isRenderTarget() const = 0;
     virtual bool isManaged() const = 0;
-    virtual int levelCount() = 0;
+    virtual int getBaseLevel() const = 0;
+    virtual int getMaxLevel() const = 0;
 
     virtual RenderTarget *getRenderTarget(int level) = 0;
     virtual RenderTarget *getRenderTargetFace(GLenum faceTarget, int level) = 0;
@@ -54,7 +55,8 @@
     virtual int getLodOffset() const;
     virtual bool isRenderTarget() const;
     virtual bool isManaged() const;
-    virtual int levelCount();
+    virtual int getBaseLevel() const;
+    virtual int getMaxLevel() const;
 
   protected:
     TextureStorage *mInstance;
@@ -72,7 +74,7 @@
 {
   public:
     TextureStorageInterface2D(Renderer *renderer, SwapChain *swapchain);
-    TextureStorageInterface2D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
+    TextureStorageInterface2D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
     virtual ~TextureStorageInterface2D();
 
     void generateMipmap(int level);
@@ -89,7 +91,7 @@
 class TextureStorageInterfaceCube : public TextureStorageInterface
 {
   public:
-    TextureStorageInterfaceCube(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, int size);
+    TextureStorageInterfaceCube(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size);
     virtual ~TextureStorageInterfaceCube();
 
     void generateMipmap(int faceIndex, int level);
@@ -106,7 +108,7 @@
 class TextureStorageInterface3D : public TextureStorageInterface
 {
   public:
-    TextureStorageInterface3D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+    TextureStorageInterface3D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                               GLsizei width, GLsizei height, GLsizei depth);
     virtual ~TextureStorageInterface3D();
 
@@ -126,7 +128,7 @@
 class TextureStorageInterface2DArray : public TextureStorageInterface
 {
   public:
-    TextureStorageInterface2DArray(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+    TextureStorageInterface2DArray(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                                    GLsizei width, GLsizei height, GLsizei depth);
     virtual ~TextureStorageInterface2DArray();
 
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
index d033230..02cadd9 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
@@ -3004,24 +3004,24 @@
     return new TextureStorage11_2D(this, swapChain11);
 }
 
-TextureStorage *Renderer11::createTextureStorage2D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
+TextureStorage *Renderer11::createTextureStorage2D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
 {
-    return new TextureStorage11_2D(this, levels, internalformat, renderTarget, width, height);
+    return new TextureStorage11_2D(this, baseLevel, maxLevel, internalformat, renderTarget, width, height);
 }
 
-TextureStorage *Renderer11::createTextureStorageCube(int levels, GLenum internalformat, bool renderTarget, int size)
+TextureStorage *Renderer11::createTextureStorageCube(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size)
 {
-    return new TextureStorage11_Cube(this, levels, internalformat, renderTarget, size);
+    return new TextureStorage11_Cube(this, baseLevel, maxLevel, internalformat, renderTarget, size);
 }
 
-TextureStorage *Renderer11::createTextureStorage3D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
+TextureStorage *Renderer11::createTextureStorage3D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
 {
-    return new TextureStorage11_3D(this, levels, internalformat, renderTarget, width, height, depth);
+    return new TextureStorage11_3D(this, baseLevel, maxLevel, internalformat, renderTarget, width, height, depth);
 }
 
-TextureStorage *Renderer11::createTextureStorage2DArray(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
+TextureStorage *Renderer11::createTextureStorage2DArray(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
 {
-    return new TextureStorage11_2DArray(this, levels, internalformat, renderTarget, width, height, depth);
+    return new TextureStorage11_2DArray(this, baseLevel, maxLevel, internalformat, renderTarget, width, height, depth);
 }
 
 void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area,
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.h b/src/libGLESv2/renderer/d3d11/Renderer11.h
index 9c60a14..e2c6e16 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.h
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.h
@@ -187,10 +187,10 @@
     virtual Image *createImage();
     virtual void generateMipmap(Image *dest, Image *source);
     virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain);
-    virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
-    virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, bool renderTarget, int size);
-    virtual TextureStorage *createTextureStorage3D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
-    virtual TextureStorage *createTextureStorage2DArray(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
+    virtual TextureStorage *createTextureStorage2D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
+    virtual TextureStorage *createTextureStorageCube(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size);
+    virtual TextureStorage *createTextureStorage3D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
+    virtual TextureStorage *createTextureStorage2DArray(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
 
     // Buffer creation
     virtual VertexBuffer *createVertexBuffer();
diff --git a/src/libGLESv2/renderer/d3d11/TextureStorage11.cpp b/src/libGLESv2/renderer/d3d11/TextureStorage11.cpp
index c004ba7..a092aaf 100644
--- a/src/libGLESv2/renderer/d3d11/TextureStorage11.cpp
+++ b/src/libGLESv2/renderer/d3d11/TextureStorage11.cpp
@@ -23,10 +23,11 @@
 namespace rx
 {
 
-TextureStorage11::TextureStorage11(Renderer *renderer, UINT bindFlags)
+TextureStorage11::TextureStorage11(Renderer *renderer, int baseLevel, UINT bindFlags)
     : mBindFlags(bindFlags),
       mLodOffset(0),
       mMipLevels(0),
+      mBaseLevel(baseLevel),
       mTextureFormat(DXGI_FORMAT_UNKNOWN),
       mShaderResourceFormat(DXGI_FORMAT_UNKNOWN),
       mRenderTargetFormat(DXGI_FORMAT_UNKNOWN),
@@ -88,32 +89,37 @@
     return false;
 }
 
-int TextureStorage11::levelCount()
+int TextureStorage11::getBaseLevel() const
+{
+    return mBaseLevel;
+}
+
+int TextureStorage11::getMaxLevel() const
 {
     int levels = 0;
     if (getBaseTexture())
     {
         levels = mMipLevels - getLodOffset();
     }
-    return levels;
+    return getBaseLevel() + levels;
 }
 
 int TextureStorage11::getLevelWidth(int mipLevel) const
 {
-    return std::max((static_cast<int>(mTextureWidth) >> mipLevel), 1);
+    return std::max((static_cast<int>(mTextureWidth) >> (mipLevel - mBaseLevel)), 1);
 }
 
 int TextureStorage11::getLevelHeight(int mipLevel) const
 {
-    return std::max((static_cast<int>(mTextureHeight) >> mipLevel), 1);
+    return std::max((static_cast<int>(mTextureHeight) >> (mipLevel - mBaseLevel)), 1);
 }
 
 int TextureStorage11::getLevelDepth(int mipLevel) const
 {
-    return std::max((static_cast<int>(mTextureDepth) >> mipLevel), 1);
+    return std::max((static_cast<int>(mTextureDepth) >> (mipLevel - mBaseLevel)), 1);
 }
 
-UINT TextureStorage11::getSubresourceIndex(int mipLevel, int layerTarget)
+UINT TextureStorage11::getSubresourceIndex(int mipLevel, int layerTarget) const
 {
     UINT index = 0;
     if (getBaseTexture())
@@ -201,7 +207,7 @@
 }
 
 TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain)
-    : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE)
+    : TextureStorage11(renderer, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE)
 {
     mTexture = swapchain->getOffscreenTexture();
     mSRV = swapchain->getRenderTargetShaderResource();
@@ -232,8 +238,8 @@
     mDepthStencilFormat = DXGI_FORMAT_UNKNOWN;
 }
 
-TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
-    : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
+TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
+    : TextureStorage11(renderer, baseLevel, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
 {
     mTexture = NULL;
     for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
@@ -260,7 +266,7 @@
         D3D11_TEXTURE2D_DESC desc;
         desc.Width = width;      // Compressed texture size constraints?
         desc.Height = height;
-        desc.MipLevels = (levels > 0) ? levels + mLodOffset : 0;
+        desc.MipLevels = ((maxLevel > 0) ? (maxLevel + mLodOffset - baseLevel) : 0);
         desc.ArraySize = 1;
         desc.Format = mTextureFormat;
         desc.SampleDesc.Count = 1;
@@ -319,7 +325,7 @@
 
 RenderTarget *TextureStorage11_2D::getRenderTarget(int level)
 {
-    if (level >= 0 && level < static_cast<int>(mMipLevels))
+    if (level >= getBaseLevel() && level < getMaxLevel())
     {
         if (!mRenderTarget[level])
         {
@@ -329,7 +335,7 @@
             D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
             srvDesc.Format = mShaderResourceFormat;
             srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
-            srvDesc.Texture2D.MostDetailedMip = level;
+            srvDesc.Texture2D.MostDetailedMip = level - getBaseLevel();
             srvDesc.Texture2D.MipLevels = 1;
 
             ID3D11ShaderResourceView *srv;
@@ -346,7 +352,7 @@
                 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
                 rtvDesc.Format = mRenderTargetFormat;
                 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
-                rtvDesc.Texture2D.MipSlice = level;
+                rtvDesc.Texture2D.MipSlice = level - getBaseLevel();
 
                 ID3D11RenderTargetView *rtv;
                 result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv);
@@ -434,8 +440,8 @@
     generateMipmapLayer(source, dest);
 }
 
-TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, int size)
-    : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
+TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size)
+    : TextureStorage11(renderer, baseLevel, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
 {
     mTexture = NULL;
     for (unsigned int i = 0; i < 6; i++)
@@ -466,7 +472,7 @@
         D3D11_TEXTURE2D_DESC desc;
         desc.Width = size;
         desc.Height = size;
-        desc.MipLevels = (levels > 0) ? levels + mLodOffset : 0;
+        desc.MipLevels = ((maxLevel > 0) ? (maxLevel + mLodOffset - baseLevel) : 0);
         desc.ArraySize = 6;
         desc.Format = mTextureFormat;
         desc.SampleDesc.Count = 1;
@@ -522,7 +528,7 @@
 
 RenderTarget *TextureStorage11_Cube::getRenderTargetFace(GLenum faceTarget, int level)
 {
-    if (level >= 0 && level < static_cast<int>(mMipLevels))
+    if (level >= getBaseLevel() && level < getMaxLevel())
     {
         int faceIndex = gl::TextureCubeMap::targetToIndex(faceTarget);
         if (!mRenderTarget[faceIndex][level])
@@ -533,7 +539,7 @@
             D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
             srvDesc.Format = mShaderResourceFormat;
             srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube
-            srvDesc.Texture2DArray.MostDetailedMip = level;
+            srvDesc.Texture2DArray.MostDetailedMip = level - getBaseLevel();
             srvDesc.Texture2DArray.MipLevels = 1;
             srvDesc.Texture2DArray.FirstArraySlice = faceIndex;
             srvDesc.Texture2DArray.ArraySize = 1;
@@ -552,7 +558,7 @@
                 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
                 rtvDesc.Format = mRenderTargetFormat;
                 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
-                rtvDesc.Texture2DArray.MipSlice = level;
+                rtvDesc.Texture2DArray.MipSlice = level - getBaseLevel();
                 rtvDesc.Texture2DArray.FirstArraySlice = faceIndex;
                 rtvDesc.Texture2DArray.ArraySize = 1;
 
@@ -578,7 +584,7 @@
                 dsvDesc.Format = mDepthStencilFormat;
                 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
                 dsvDesc.Flags = 0;
-                dsvDesc.Texture2DArray.MipSlice = level;
+                dsvDesc.Texture2DArray.MipSlice = level - getBaseLevel();
                 dsvDesc.Texture2DArray.FirstArraySlice = faceIndex;
                 dsvDesc.Texture2DArray.ArraySize = 1;
 
@@ -644,9 +650,9 @@
     generateMipmapLayer(source, dest);
 }
 
-TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                                          GLsizei width, GLsizei height, GLsizei depth)
-    : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
+    : TextureStorage11(renderer, baseLevel, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
 {
     mTexture = NULL;
 
@@ -675,7 +681,7 @@
         desc.Width = width;
         desc.Height = height;
         desc.Depth = depth;
-        desc.MipLevels = (levels > 0) ? levels + mLodOffset : 0;
+        desc.MipLevels = ((maxLevel > 0) ? (maxLevel + mLodOffset - baseLevel) : 0);
         desc.Format = mTextureFormat;
         desc.Usage = D3D11_USAGE_DEFAULT;
         desc.BindFlags = getBindFlags();
@@ -761,7 +767,7 @@
 
 RenderTarget *TextureStorage11_3D::getRenderTarget(int mipLevel)
 {
-    if (mipLevel >= 0 && mipLevel < static_cast<int>(mMipLevels))
+    if (mipLevel >= getBaseLevel() && mipLevel < getMaxLevel())
     {
         if (!mLevelRenderTargets[mipLevel])
         {
@@ -771,7 +777,7 @@
             D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
             srvDesc.Format = mShaderResourceFormat;
             srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
-            srvDesc.Texture3D.MostDetailedMip = mipLevel;
+            srvDesc.Texture3D.MostDetailedMip = mipLevel - getBaseLevel();
             srvDesc.Texture3D.MipLevels = 1;
 
             ID3D11ShaderResourceView *srv;
@@ -788,7 +794,7 @@
                 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
                 rtvDesc.Format = mRenderTargetFormat;
                 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
-                rtvDesc.Texture3D.MipSlice = mipLevel;
+                rtvDesc.Texture3D.MipSlice = mipLevel - getBaseLevel();
                 rtvDesc.Texture3D.FirstWSlice = 0;
                 rtvDesc.Texture3D.WSize = -1;
 
@@ -824,7 +830,7 @@
 
 RenderTarget *TextureStorage11_3D::getRenderTargetLayer(int mipLevel, int layer)
 {
-    if (mipLevel >= 0 && mipLevel < static_cast<int>(mMipLevels))
+    if (mipLevel >= getBaseLevel() && mipLevel < getMaxLevel())
     {
         LevelLayerKey key(mipLevel, layer);
         if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end())
@@ -840,7 +846,7 @@
                 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
                 rtvDesc.Format = mRenderTargetFormat;
                 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
-                rtvDesc.Texture3D.MipSlice = mipLevel;
+                rtvDesc.Texture3D.MipSlice = mipLevel - getBaseLevel();
                 rtvDesc.Texture3D.FirstWSlice = layer;
                 rtvDesc.Texture3D.WSize = 1;
 
@@ -882,9 +888,9 @@
     generateMipmapLayer(source, dest);
 }
 
-TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                                                    GLsizei width, GLsizei height, GLsizei depth)
-    : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
+    : TextureStorage11(renderer, baseLevel, GetTextureBindFlags(internalformat, renderer->getCurrentClientVersion(), renderTarget))
 {
     mTexture = NULL;
 
@@ -907,7 +913,7 @@
         D3D11_TEXTURE2D_DESC desc;
         desc.Width = width;
         desc.Height = height;
-        desc.MipLevels = (levels > 0) ? levels + mLodOffset : 0;
+        desc.MipLevels = ((maxLevel > 0) ? (maxLevel + mLodOffset - baseLevel) : 0);
         desc.ArraySize = depth;
         desc.Format = mTextureFormat;
         desc.SampleDesc.Count = 1;
@@ -1004,7 +1010,7 @@
             D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
             srvDesc.Format = mShaderResourceFormat;
             srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
-            srvDesc.Texture2DArray.MostDetailedMip = mipLevel;
+            srvDesc.Texture2DArray.MostDetailedMip = mipLevel - getBaseLevel();
             srvDesc.Texture2DArray.MipLevels = 1;
             srvDesc.Texture2DArray.FirstArraySlice = layer;
             srvDesc.Texture2DArray.ArraySize = 1;
@@ -1023,7 +1029,7 @@
                 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
                 rtvDesc.Format = mRenderTargetFormat;
                 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
-                rtvDesc.Texture2DArray.MipSlice = mipLevel;
+                rtvDesc.Texture2DArray.MipSlice = mipLevel - getBaseLevel();
                 rtvDesc.Texture2DArray.FirstArraySlice = layer;
                 rtvDesc.Texture2DArray.ArraySize = 1;
 
diff --git a/src/libGLESv2/renderer/d3d11/TextureStorage11.h b/src/libGLESv2/renderer/d3d11/TextureStorage11.h
index 20761e9..a5d2b75 100644
--- a/src/libGLESv2/renderer/d3d11/TextureStorage11.h
+++ b/src/libGLESv2/renderer/d3d11/TextureStorage11.h
@@ -24,7 +24,6 @@
 class TextureStorage11 : public TextureStorage
 {
   public:
-    TextureStorage11(Renderer *renderer, UINT bindFlags);
     virtual ~TextureStorage11();
 
     static TextureStorage11 *makeTextureStorage11(TextureStorage *storage);
@@ -45,14 +44,16 @@
     virtual int getLodOffset() const;
     virtual bool isRenderTarget() const;
     virtual bool isManaged() const;
-    virtual int levelCount();
-    UINT getSubresourceIndex(int mipLevel, int layerTarget);
+    virtual int getBaseLevel() const;
+    virtual int getMaxLevel() const;
+    UINT getSubresourceIndex(int mipLevel, int layerTarget) const;
 
     bool updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, int level,
                                 int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
                                 GLsizei width, GLsizei height, GLsizei depth);
 
   protected:
+    TextureStorage11(Renderer *renderer, int baseLevel, UINT bindFlags);
     void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest);
     int getLevelWidth(int mipLevel) const;
     int getLevelHeight(int mipLevel) const;
@@ -61,6 +62,7 @@
     Renderer11 *mRenderer;
     int mLodOffset;
     unsigned int mMipLevels;
+    int mBaseLevel;
 
     DXGI_FORMAT mTextureFormat;
     DXGI_FORMAT mShaderResourceFormat;
@@ -82,7 +84,7 @@
 {
   public:
     TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain);
-    TextureStorage11_2D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
+    TextureStorage11_2D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
     virtual ~TextureStorage11_2D();
 
     static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage);
@@ -103,7 +105,7 @@
 class TextureStorage11_Cube : public TextureStorage11
 {
   public:
-    TextureStorage11_Cube(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, int size);
+    TextureStorage11_Cube(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size);
     virtual ~TextureStorage11_Cube();
 
     static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage);
@@ -124,7 +126,7 @@
 class TextureStorage11_3D : public TextureStorage11
 {
   public:
-    TextureStorage11_3D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+    TextureStorage11_3D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                         GLsizei width, GLsizei height, GLsizei depth);
     virtual ~TextureStorage11_3D();
 
@@ -152,7 +154,7 @@
 class TextureStorage11_2DArray : public TextureStorage11
 {
   public:
-    TextureStorage11_2DArray(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget,
+    TextureStorage11_2DArray(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget,
                              GLsizei width, GLsizei height, GLsizei depth);
     virtual ~TextureStorage11_2DArray();
 
diff --git a/src/libGLESv2/renderer/d3d9/Renderer9.cpp b/src/libGLESv2/renderer/d3d9/Renderer9.cpp
index 1a5b3c6..ecbf613 100644
--- a/src/libGLESv2/renderer/d3d9/Renderer9.cpp
+++ b/src/libGLESv2/renderer/d3d9/Renderer9.cpp
@@ -2658,7 +2658,7 @@
         TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source->getStorageInstance());
         TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest->getStorageInstance());
 
-        int levels = source9->levelCount();
+        int levels = source9->getMaxLevel() - source9->getBaseLevel();
         for (int i = 0; i < levels; ++i)
         {
             IDirect3DSurface9 *srcSurf = source9->getSurfaceLevel(i, false);
@@ -2687,7 +2687,7 @@
     {
         TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source->getStorageInstance());
         TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest->getStorageInstance());
-        int levels = source9->levelCount();
+        int levels = source9->getMaxLevel() - source9->getBaseLevel();
         for (int f = 0; f < 6; f++)
         {
             for (int i = 0; i < levels; i++)
@@ -3313,17 +3313,17 @@
     return new TextureStorage9_2D(this, swapChain9);
 }
 
-TextureStorage *Renderer9::createTextureStorage2D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
+TextureStorage *Renderer9::createTextureStorage2D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
 {
-    return new TextureStorage9_2D(this, levels, internalformat, renderTarget, width, height);
+    return new TextureStorage9_2D(this, baseLevel, maxLevel, internalformat, renderTarget, width, height);
 }
 
-TextureStorage *Renderer9::createTextureStorageCube(int levels, GLenum internalformat, bool renderTarget, int size)
+TextureStorage *Renderer9::createTextureStorageCube(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size)
 {
-    return new TextureStorage9_Cube(this, levels, internalformat, renderTarget, size);
+    return new TextureStorage9_Cube(this, baseLevel, maxLevel, internalformat, renderTarget, size);
 }
 
-TextureStorage *Renderer9::createTextureStorage3D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
+TextureStorage *Renderer9::createTextureStorage3D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
 {
     // 3D textures are not supported by the D3D9 backend.
     UNREACHABLE();
@@ -3331,7 +3331,7 @@
     return NULL;
 }
 
-TextureStorage *Renderer9::createTextureStorage2DArray(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
+TextureStorage *Renderer9::createTextureStorage2DArray(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth)
 {
     // 2D array textures are not supported by the D3D9 backend.
     UNREACHABLE();
diff --git a/src/libGLESv2/renderer/d3d9/Renderer9.h b/src/libGLESv2/renderer/d3d9/Renderer9.h
index 5bddd5e..dfcbb60 100644
--- a/src/libGLESv2/renderer/d3d9/Renderer9.h
+++ b/src/libGLESv2/renderer/d3d9/Renderer9.h
@@ -203,10 +203,10 @@
     virtual Image *createImage();
     virtual void generateMipmap(Image *dest, Image *source);
     virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain);
-    virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
-    virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, bool renderTarget, int size);
-    virtual TextureStorage *createTextureStorage3D(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
-    virtual TextureStorage *createTextureStorage2DArray(int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
+    virtual TextureStorage *createTextureStorage2D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
+    virtual TextureStorage *createTextureStorageCube(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size);
+    virtual TextureStorage *createTextureStorage3D(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
+    virtual TextureStorage *createTextureStorage2DArray(int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth);
 
     // Buffer creation
     virtual VertexBuffer *createVertexBuffer();
diff --git a/src/libGLESv2/renderer/d3d9/TextureStorage9.cpp b/src/libGLESv2/renderer/d3d9/TextureStorage9.cpp
index 48699da..77334b2 100644
--- a/src/libGLESv2/renderer/d3d9/TextureStorage9.cpp
+++ b/src/libGLESv2/renderer/d3d9/TextureStorage9.cpp
@@ -20,8 +20,9 @@
 
 namespace rx
 {
-TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage)
+TextureStorage9::TextureStorage9(Renderer *renderer, int baseLevel, DWORD usage)
     : mLodOffset(0),
+      mBaseLevel(baseLevel),
       mRenderer(Renderer9::makeRenderer9(renderer)),
       mD3DUsage(usage),
       mD3DPool(mRenderer->getTexturePool(usage))
@@ -83,12 +84,18 @@
     return mLodOffset;
 }
 
-int TextureStorage9::levelCount()
+int TextureStorage9::getBaseLevel() const
 {
-    return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
+    return mBaseLevel;
 }
 
-TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
+int TextureStorage9::getMaxLevel() const
+{
+    return getBaseLevel() + (getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0);
+}
+
+TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain)
+    : TextureStorage9(renderer, 0, D3DUSAGE_RENDERTARGET)
 {
     IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
     mTexture = surfaceTexture;
@@ -97,8 +104,8 @@
     initializeRenderTarget();
 }
 
-TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
-    : TextureStorage9(renderer, GetTextureUsage(internalformat, Renderer9::makeRenderer9(renderer), renderTarget))
+TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height)
+    : TextureStorage9(renderer, baseLevel, GetTextureUsage(internalformat, Renderer9::makeRenderer9(renderer), renderTarget))
 {
     mTexture = NULL;
     mRenderTarget = NULL;
@@ -109,8 +116,9 @@
         IDirect3DDevice9 *device = mRenderer->getDevice();
         D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat, mRenderer);
         d3d9::MakeValidSize(false, format, &width, &height, &mLodOffset);
-        HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
-                                               format, getPool(), &mTexture, NULL);
+        UINT creationLevels = (maxLevel ? maxLevel + mLodOffset : 0);
+
+        HRESULT result = device->CreateTexture(width, height, creationLevels, getUsage(), format, getPool(), &mTexture, NULL);
 
         if (FAILED(result))
         {
@@ -191,8 +199,8 @@
     }
 }
 
-TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, int size)
-    : TextureStorage9(renderer, GetTextureUsage(internalformat, Renderer9::makeRenderer9(renderer), renderTarget))
+TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size)
+    : TextureStorage9(renderer, baseLevel, GetTextureUsage(internalformat, Renderer9::makeRenderer9(renderer), renderTarget))
 {
     mTexture = NULL;
     for (int i = 0; i < 6; ++i)
@@ -208,8 +216,9 @@
         int height = size;
         D3DFORMAT format = gl_d3d9::GetTextureFormat(internalformat, mRenderer);
         d3d9::MakeValidSize(false, format, &size, &height, &mLodOffset);
-        HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
-                                                   format, getPool(), &mTexture, NULL);
+        UINT creationLevels = (maxLevel ? maxLevel + mLodOffset : 0);
+
+        HRESULT result = device->CreateCubeTexture(size, creationLevels, getUsage(), format, getPool(), &mTexture, NULL);
 
         if (FAILED(result))
         {
diff --git a/src/libGLESv2/renderer/d3d9/TextureStorage9.h b/src/libGLESv2/renderer/d3d9/TextureStorage9.h
index 8a61a01..3a512f7 100644
--- a/src/libGLESv2/renderer/d3d9/TextureStorage9.h
+++ b/src/libGLESv2/renderer/d3d9/TextureStorage9.h
@@ -24,7 +24,6 @@
 class TextureStorage9 : public TextureStorage
 {
   public:
-    TextureStorage9(Renderer *renderer, DWORD usage);
     virtual ~TextureStorage9();
 
     static TextureStorage9 *makeTextureStorage9(TextureStorage *storage);
@@ -44,12 +43,16 @@
     virtual int getLodOffset() const;
     virtual bool isRenderTarget() const;
     virtual bool isManaged() const;
-    virtual int levelCount();
+    virtual int getBaseLevel() const;
+    virtual int getMaxLevel() const;
 
   protected:
     int mLodOffset;
+    int mBaseLevel;
     Renderer9 *mRenderer;
 
+    TextureStorage9(Renderer *renderer, int baseLevel, DWORD usage);
+
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureStorage9);
 
@@ -61,7 +64,7 @@
 {
   public:
     TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain);
-    TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
+    TextureStorage9_2D(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height);
     virtual ~TextureStorage9_2D();
 
     static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage);
@@ -83,7 +86,7 @@
 class TextureStorage9_Cube : public TextureStorage9
 {
   public:
-    TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, bool renderTarget, int size);
+    TextureStorage9_Cube(Renderer *renderer, int baseLevel, int maxLevel, GLenum internalformat, bool renderTarget, int size);
     virtual ~TextureStorage9_Cube();
 
     static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage);