Workaround Intel driver bug on D3D when renderering with no render target

When rendering with no render target on D3D, two bugs lead to
incorrect behavior on Intel drivers < 4815. The rendering samples
always pass neglecting discard statement in pixel shader.

Two bugs are listed bellow,
1. When a framebuffer has no attachments, the pixel shader will be
recompiled to drop 'SV_TARGET'. On Intel drivers, when using a pixel
shader with no 'SV_TARGET' in a draw, pixels are always generated even
if they should be discard by 'discard' statements.

2. When a framebuffer has no attachments, ID3D11BlendState.RenderTarget
[].RenderTargetWriteMask were set to 0 in angle. If RenderTargetWriteMask
is 0 and rendertarget is not set, then rendering samples also pass
neglecting discard statement in pixel shader on Intel.

So we add a dummy texture as render target to workaround this issue.

BUG=angleproject:2152

TEST=FramebufferTest_ES31.RenderingLimitToDefaultFBOSizeWithNoAttachments/ES3_1_D3D11
TEST=dEQP-GLES31.functional.fbo.no_attachments.*
TEST=dEQP-GLES31.functional.state_query.integer.max_framebuffer*
TEST=dEQP-GLES31.functional.state_query.integer.max_color_texture_samples_*
TEST=dEQP-GLES31.functional.state_query.integer.max_depth_texture_samples_*
TEST=dEQP-GLES31.functional.state_query.integer.max_integer_samples_*

Change-Id: I1cb974703b6c05c39b731d147f7c8c4fb7b5fe68
Reviewed-on: https://chromium-review.googlesource.com/741544
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/FramebufferD3D.cpp b/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
index 01d2761..0c85ccf 100644
--- a/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
+++ b/src/libANGLE/renderer/d3d/FramebufferD3D.cpp
@@ -369,6 +369,29 @@
         }
     }
 
+    // When rendering with no render target on D3D, two bugs lead to incorrect behavior on Intel
+    // drivers < 4815. The rendering samples always pass neglecting discard statements in pixel
+    // shader. We add a dummy texture as render target in such case.
+    if (mRenderer->getWorkarounds().addDummyTextureNoRenderTarget &&
+        colorAttachmentsForRender.empty())
+    {
+        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>(
+            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)
+        {
+            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);
+        }
+    }
+
     mColorAttachmentsForRender = std::move(colorAttachmentsForRender);
     mCurrentActiveProgramOutputs = activeProgramOutputs;