Fix addDummyTextureNoRenderTarget workaround memory leak

Add dummy attachment in FramebufferD3D as a private member and release
the dummy attchment in destory of FramebufferD3D.

BUG=angleproject:2282

TEST=FramebufferTest_ES31.RenderingLimitToDefaultFBOSizeWithNoAttachments/ES3_1_D3D11
TEST=dEQP-GLES31.functional.fbo.no_attachments.*

Change-Id: I3a17282ef132185fbc25f4076f624e53661d4b20
Reviewed-on: https://chromium-review.googlesource.com/831847
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/FramebufferD3D.cpp b/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
index fbe8cdf..aea2b28 100644
--- a/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
+++ b/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
@@ -92,7 +92,7 @@
 ClearParameters::ClearParameters(const ClearParameters &other) = default;
 
 FramebufferD3D::FramebufferD3D(const gl::FramebufferState &data, RendererD3D *renderer)
-    : FramebufferImpl(data), mRenderer(renderer)
+    : FramebufferImpl(data), mRenderer(renderer), mDummyAttachment()
 {
 }
 
@@ -381,18 +381,35 @@
     {
         static_assert(static_cast<size_t>(activeProgramOutputs.size()) <= 32,
                       "Size of active program outputs should less or equal than 32.");
-        GLenum i = static_cast<GLenum>(
+        const GLuint activeProgramLocation = static_cast<GLuint>(
             gl::ScanForward(static_cast<uint32_t>(activeProgramOutputs.bits())));
 
-        gl::Texture *dummyTex = nullptr;
-        // TODO(Jamie): Handle error if dummy texture can't be created.
-        ANGLE_SWALLOW_ERR(mRenderer->getIncompleteTexture(context, GL_TEXTURE_2D, &dummyTex));
-        if (dummyTex)
+        if (mDummyAttachment.isAttached() &&
+            (mDummyAttachment.getBinding() - GL_COLOR_ATTACHMENT0) == activeProgramLocation)
         {
-            gl::ImageIndex index                   = gl::ImageIndex::Make2D(0);
-            gl::FramebufferAttachment *dummyAttach = new gl::FramebufferAttachment(
-                context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + i, index, dummyTex);
-            colorAttachmentsForRender.push_back(dummyAttach);
+            colorAttachmentsForRender.push_back(&mDummyAttachment);
+        }
+        else
+        {
+            // Remove dummy attachment to prevents us from leaking it, and the program may require
+            // it to be attached to a new binding point.
+            if (mDummyAttachment.isAttached())
+            {
+                mDummyAttachment.detach(context);
+            }
+
+            gl::Texture *dummyTex = nullptr;
+            // TODO(Jamie): Handle error if dummy texture can't be created.
+            ANGLE_SWALLOW_ERR(mRenderer->getIncompleteTexture(context, GL_TEXTURE_2D, &dummyTex));
+            if (dummyTex)
+            {
+
+                gl::ImageIndex index = gl::ImageIndex::Make2D(0);
+                mDummyAttachment     = gl::FramebufferAttachment(
+                    context, GL_TEXTURE, GL_COLOR_ATTACHMENT0_EXT + activeProgramLocation, index,
+                    dummyTex);
+                colorAttachmentsForRender.push_back(&mDummyAttachment);
+            }
         }
     }
 
@@ -402,4 +419,12 @@
     return mColorAttachmentsForRender.value();
 }
 
+void FramebufferD3D::destroy(const gl::Context *context)
+{
+    if (mDummyAttachment.isAttached())
+    {
+        mDummyAttachment.detach(context);
+    }
+}
+
 }  // namespace rx