Updated Renderbuffers, Textures and TextureStorageInterface to be aware of render targets which are based on miplevels and layers other than zero.

TRAC #23470

Signed-off-by: Jamie Madill
Signed-off-by: Shannon Woods
Author: Geoff Lang
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index cf247fc..425dee9 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -73,6 +73,16 @@
     return mTarget;
 }
 
+void Texture::addProxyRef(const Renderbuffer *proxy)
+{
+    mRenderbufferProxies.addRef(proxy);
+}
+
+void Texture::releaseProxy(const Renderbuffer *proxy)
+{
+    mRenderbufferProxies.release(proxy);
+}
+
 // Returns true on successful filter state update (valid enum parameter)
 bool Texture::setMinFilter(GLenum filter)
 {
@@ -330,12 +340,6 @@
     return texture ? texture->getTextureSerial() : 0;
 }
 
-unsigned int Texture::getRenderTargetSerial(GLenum target)
-{
-    rx::TextureStorageInterface *texture = getStorage(true);
-    return texture ? texture->getRenderTargetSerial(target) : 0;
-}
-
 bool Texture::isImmutable() const
 {
     return mImmutable;
@@ -369,8 +373,6 @@
 {
     mTexStorage = NULL;
     mSurface = NULL;
-    mColorbufferProxy = NULL;
-    mProxyRefs = 0;
 
     for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
     {
@@ -380,8 +382,6 @@
 
 Texture2D::~Texture2D()
 {
-    mColorbufferProxy = NULL;
-
     delete mTexStorage;
     mTexStorage = NULL;
     
@@ -397,23 +397,6 @@
     }
 }
 
-// We need to maintain a count of references to renderbuffers acting as 
-// proxies for this texture, so that we do not attempt to use a pointer 
-// to a renderbuffer proxy which has been deleted.
-void Texture2D::addProxyRef(const Renderbuffer *proxy)
-{
-    mProxyRefs++;
-}
-
-void Texture2D::releaseProxy(const Renderbuffer *proxy)
-{
-    if (mProxyRefs > 0)
-        mProxyRefs--;
-
-    if (mProxyRefs == 0)
-        mColorbufferProxy = NULL;
-}
-
 GLsizei Texture2D::getWidth(GLint level) const
 {
     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
@@ -919,25 +902,30 @@
     }
 }
 
-Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
+Renderbuffer *Texture2D::getRenderbuffer(GLint level)
 {
-    if (target != GL_TEXTURE_2D)
+    Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, 0);
+    if (!renderBuffer)
     {
-        return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+        renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, level));
+        mRenderbufferProxies.add(level, 0, renderBuffer);
     }
 
-    if (mColorbufferProxy == NULL)
-    {
-        mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
-    }
-
-    return mColorbufferProxy;
+    return renderBuffer;
 }
 
-rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
+unsigned int Texture2D::getRenderTargetSerial(GLint level)
 {
-    ASSERT(target == GL_TEXTURE_2D);
+    if (!mTexStorage || !mTexStorage->isRenderTarget())
+    {
+        convertToRenderTarget();
+    }
 
+    return mTexStorage ? mTexStorage->getRenderTargetSerial(level) : 0;
+}
+
+rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
+{
     // ensure the underlying texture is created
     if (getStorage(true) == NULL)
     {
@@ -945,20 +933,18 @@
     }
 
     updateTexture();
-    
+
     // ensure this is NOT a depth texture
-    if (isDepth(0))
+    if (isDepth(level))
     {
         return NULL;
     }
 
-    return mTexStorage->getRenderTarget();
+    return mTexStorage->getRenderTarget(level);
 }
 
-rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
+rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
 {
-    ASSERT(target == GL_TEXTURE_2D);
-
     // ensure the underlying texture is created
     if (getStorage(true) == NULL)
     {
@@ -968,11 +954,12 @@
     updateTexture();
 
     // ensure this is actually a depth texture
-    if (!isDepth(0))
+    if (!isDepth(level))
     {
         return NULL;
     }
-    return mTexStorage->getRenderTarget();
+
+    return mTexStorage->getRenderTarget(level);
 }
 
 int Texture2D::levelCount()
@@ -1002,9 +989,6 @@
     mTexStorage = NULL;
     for (int i = 0; i < 6; i++)
     {
-        mFaceProxies[i] = NULL;
-        mFaceProxyRefs[i] = 0;
-
         for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
         {
             mImageArray[i][j] = renderer->createImage();
@@ -1016,8 +1000,6 @@
 {
     for (int i = 0; i < 6; i++)
     {
-        mFaceProxies[i] = NULL;
-
         for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
         {
             delete mImageArray[i][j];
@@ -1028,35 +1010,6 @@
     mTexStorage = NULL;
 }
 
-// We need to maintain a count of references to renderbuffers acting as 
-// proxies for this texture, so that the texture is not deleted while 
-// proxy references still exist. If the reference count drops to zero,
-// we set our proxy pointer NULL, so that a new attempt at referencing
-// will cause recreation.
-void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
-{
-    for (int i = 0; i < 6; i++)
-    {
-        if (mFaceProxies[i] == proxy)
-            mFaceProxyRefs[i]++;
-    }
-}
-
-void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
-{
-    for (int i = 0; i < 6; i++)
-    {
-        if (mFaceProxies[i] == proxy)
-        {
-            if (mFaceProxyRefs[i] > 0)
-                mFaceProxyRefs[i]--;
-
-            if (mFaceProxyRefs[i] == 0)
-                mFaceProxies[i] = NULL;
-        }
-    }
-}
-
 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
 {
     if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
@@ -1288,6 +1241,11 @@
     return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
 }
 
+bool TextureCubeMap::isDepth(GLenum target, GLint level) const
+{
+    return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
+}
+
 // Constructs a native texture resource from the texture images, or returns an existing one
 void TextureCubeMap::createTexture()
 {
@@ -1596,7 +1554,7 @@
     }
 }
 
-Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
+Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
 {
     if (!IsCubemapTextureTarget(target))
     {
@@ -1605,15 +1563,27 @@
 
     unsigned int face = faceIndex(target);
 
-    if (mFaceProxies[face] == NULL)
+    Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, face);
+    if (!renderBuffer)
     {
-        mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
+        renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target, level));
+        mRenderbufferProxies.add(level, face, renderBuffer);
     }
 
-    return mFaceProxies[face];
+    return renderBuffer;
 }
 
-rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
+unsigned int TextureCubeMap::getRenderTargetSerial(GLenum faceTarget, GLint level)
+{
+    if (!mTexStorage || !mTexStorage->isRenderTarget())
+    {
+        convertToRenderTarget();
+    }
+
+    return mTexStorage ? mTexStorage->getRenderTargetSerial(faceTarget, level) : 0;
+}
+
+rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
 {
     ASSERT(IsCubemapTextureTarget(target));
 
@@ -1624,8 +1594,35 @@
     }
 
     updateTexture();
-    
-    return mTexStorage->getRenderTarget(target);
+
+    // ensure this is NOT a depth texture
+    if (isDepth(target, level))
+    {
+        return NULL;
+    }
+
+    return mTexStorage->getRenderTarget(target, level);
+}
+
+rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
+{
+    ASSERT(IsCubemapTextureTarget(target));
+
+    // ensure the underlying texture is created
+    if (getStorage(true) == NULL)
+    {
+        return NULL;
+    }
+
+    updateTexture();
+
+    // ensure this is a depth texture
+    if (!isDepth(target, level))
+    {
+        return NULL;
+    }
+
+    return mTexStorage->getRenderTarget(target, level);
 }
 
 int TextureCubeMap::levelCount()
@@ -1653,8 +1650,6 @@
 Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
 {
     mTexStorage = NULL;
-    mColorbufferProxy = NULL;
-    mProxyRefs = 0;
 
     for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
     {
@@ -1664,8 +1659,6 @@
 
 Texture3D::~Texture3D()
 {
-    mColorbufferProxy = NULL;
-
     delete mTexStorage;
     mTexStorage = NULL;
 
@@ -1675,20 +1668,6 @@
     }
 }
 
-void Texture3D::addProxyRef(const Renderbuffer *proxy)
-{
-    mProxyRefs++;
-}
-
-void Texture3D::releaseProxy(const Renderbuffer *proxy)
-{
-    if (mProxyRefs > 0)
-        mProxyRefs--;
-
-    if (mProxyRefs == 0)
-        mColorbufferProxy = NULL;
-}
-
 GLsizei Texture3D::getWidth(GLint level) const
 {
     return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
@@ -1958,10 +1937,27 @@
     return true;
 }
 
-Renderbuffer *Texture3D::getRenderbuffer(GLenum target)
+Renderbuffer *Texture3D::getRenderbuffer(GLint level, GLint layer)
 {
-    UNIMPLEMENTED();
-    return NULL;
+    Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
+    if (!renderBuffer)
+    {
+        UNIMPLEMENTED();
+        //renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture3DLayer(this, level, layer));
+        //mRenderbufferProxies.add(level, 0, renderBuffer);
+    }
+
+    return renderBuffer;
+}
+
+unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
+{
+    if (!mTexStorage || !mTexStorage->isRenderTarget())
+    {
+        convertToRenderTarget();
+    }
+
+    return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
 }
 
 int Texture3D::levelCount()
@@ -2049,10 +2045,42 @@
     mDirtyImages = true;
 }
 
-rx::RenderTarget *Texture3D::getRenderTarget(GLenum target)
+rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
 {
-    UNIMPLEMENTED();
-    return NULL;
+    // ensure the underlying texture is created
+    if (getStorage(true) == NULL)
+    {
+        return NULL;
+    }
+
+    updateTexture();
+
+    // ensure this is NOT a depth texture
+    if (isDepth(level))
+    {
+        return NULL;
+    }
+
+    return mTexStorage->getRenderTarget(level, layer);
+}
+
+rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
+{
+    // ensure the underlying texture is created
+    if (getStorage(true) == NULL)
+    {
+        return NULL;
+    }
+
+    updateTexture();
+
+    // ensure this is a depth texture
+    if (!isDepth(level))
+    {
+        return NULL;
+    }
+
+    return mTexStorage->getRenderTarget(level, layer);
 }
 
 rx::TextureStorageInterface *Texture3D::getStorage(bool renderTarget)
@@ -2119,8 +2147,6 @@
 Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
 {
     mTexStorage = NULL;
-    mColorbufferProxy = NULL;
-    mProxyRefs = 0;
 
     for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
     {
@@ -2131,8 +2157,6 @@
 
 Texture2DArray::~Texture2DArray()
 {
-    mColorbufferProxy = NULL;
-
     delete mTexStorage;
     mTexStorage = NULL;
     for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
@@ -2145,20 +2169,6 @@
     }
 }
 
-void Texture2DArray::addProxyRef(const Renderbuffer *proxy)
-{
-    mProxyRefs++;
-}
-
-void Texture2DArray::releaseProxy(const Renderbuffer *proxy)
-{
-    if (mProxyRefs > 0)
-        mProxyRefs--;
-
-    if (mProxyRefs == 0)
-        mColorbufferProxy = NULL;
-}
-
 GLsizei Texture2DArray::getWidth(GLint level) const
 {
     return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
@@ -2475,10 +2485,27 @@
     return true;
 }
 
-Renderbuffer *Texture2DArray::getRenderbuffer(GLenum target)
+Renderbuffer *Texture2DArray::getRenderbuffer(GLint level, GLint layer)
 {
-    UNIMPLEMENTED();
-    return NULL;
+    Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, layer);
+    if (!renderBuffer)
+    {
+        UNIMPLEMENTED();
+        //renderBuffer = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2DArrayLayer(this, level, layer));
+        //mRenderbufferProxies.add(level, 0, renderBuffer);
+    }
+
+    return renderBuffer;
+}
+
+unsigned int Texture2DArray::getRenderTargetSerial( GLint level, GLint layer )
+{
+    if (!mTexStorage || !mTexStorage->isRenderTarget())
+    {
+        convertToRenderTarget();
+    }
+
+    return mTexStorage ? mTexStorage->getRenderTargetSerial(level, layer) : 0;
 }
 
 int Texture2DArray::levelCount()
@@ -2571,10 +2598,42 @@
     mDirtyImages = true;
 }
 
-rx::RenderTarget *Texture2DArray::getRenderTarget(GLenum target)
+rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
 {
-    UNIMPLEMENTED();
-    return NULL;
+    // ensure the underlying texture is created
+    if (getStorage(true) == NULL)
+    {
+        return NULL;
+    }
+
+    updateTexture();
+
+    // ensure this is NOT a depth texture
+    if (isDepth(level))
+    {
+        return NULL;
+    }
+
+    return mTexStorage->getRenderTarget(level, layer);
+}
+
+rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
+{
+    // ensure the underlying texture is created
+    if (getStorage(true) == NULL)
+    {
+        return NULL;
+    }
+
+    updateTexture();
+
+    // ensure this is a depth texture
+    if (!isDepth(level))
+    {
+        return NULL;
+    }
+
+    return mTexStorage->getRenderTarget(level, layer);
 }
 
 rx::TextureStorageInterface *Texture2DArray::getStorage(bool renderTarget)