Attempt to ensure pipeline flush on rendertarget change

Some ATI cards appear not to flush the pipeline correctly, causing textures not to pick up newly-drawn contexts, so do an extra no-op draw when necessary.

BUG=169
TEST=chromium on hulu.com

Review URL: http://codereview.appspot.com/4576051

git-svn-id: http://angleproject.googlecode.com/svn/trunk@693 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/common/version.h b/src/common/version.h
index 8a075e9..b7ebb8f 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -1,7 +1,7 @@
 #define MAJOR_VERSION 0
 #define MINOR_VERSION 0
 #define BUILD_VERSION 0
-#define BUILD_REVISION 692
+#define BUILD_REVISION 693
 
 #define STRINGIFY(x) #x
 #define MACRO_STRINGIFY(x) STRINGIFY(x)
diff --git a/src/libEGL/Display.cpp b/src/libEGL/Display.cpp
index b8b5e2f..1d64f9a 100644
--- a/src/libEGL/Display.cpp
+++ b/src/libEGL/Display.cpp
@@ -141,6 +141,8 @@
         if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)     {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);}
         if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)      {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);}
 
+        mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
+
         const D3DFORMAT renderTargetFormats[] =
         {
             D3DFMT_A1R5G5B5,
@@ -688,6 +690,11 @@
     return mDeviceCaps;
 }
 
+D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier()
+{
+    return &mAdapterIdentifier;
+}
+
 bool Display::isDeviceLost()
 {
     if (mDeviceEx)
diff --git a/src/libEGL/Display.h b/src/libEGL/Display.h
index f377db4..86de5cd 100644
--- a/src/libEGL/Display.h
+++ b/src/libEGL/Display.h
@@ -60,6 +60,7 @@
 
     virtual IDirect3DDevice9 *getDevice();
     virtual D3DCAPS9 getDeviceCaps();
+    virtual D3DADAPTER_IDENTIFIER9 *getAdapterIdentifier();
     bool isDeviceLost();
     virtual void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray);
     virtual bool getCompressedTextureSupport();
@@ -91,6 +92,7 @@
     IDirect3DDevice9 *mDevice;
     IDirect3DDevice9Ex *mDeviceEx;  // Might be null if D3D9Ex is not supported.
     D3DCAPS9 mDeviceCaps;
+    D3DADAPTER_IDENTIFIER9 mAdapterIdentifier;
     HWND mDeviceWindow;
 
     bool mSceneStarted;
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 1c66450..6c973ea 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -1737,6 +1737,15 @@
     GLint alwaysFront = !isTriangleMode(drawMode);
     programObject->setUniform1iv(pointsOrLines, 1, &alwaysFront);
 
+    egl::Display *display = getDisplay();
+    D3DADAPTER_IDENTIFIER9 *identifier = display->getAdapterIdentifier();
+    bool zeroColorMaskAllowed = identifier->VendorId != 0x1002;
+    // Apparently some ATI cards have a bug where a draw with a zero color
+    // write mask can cause later draws to have incorrect results. Instead,
+    // set a nonzero color write mask but modify the blend state so that no
+    // drawing is done.
+    // http://code.google.com/p/angleproject/issues/detail?id=169
+
     if (mCullStateDirty || mFrontFaceDirty)
     {
         if (mState.cullFace)
@@ -1766,6 +1775,12 @@
         mDepthStateDirty = false;
     }
 
+    if (!zeroColorMaskAllowed && (mMaskStateDirty || mBlendStateDirty))
+    {
+        mBlendStateDirty = true;
+        mMaskStateDirty = true;
+    }
+
     if (mBlendStateDirty)
     {
         if (mState.blend)
@@ -1874,8 +1889,22 @@
 
     if (mMaskStateDirty)
     {
-        device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, 
-                                                                               mState.colorMaskBlue, mState.colorMaskAlpha));
+        int colorMask = es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, 
+                                                mState.colorMaskBlue, mState.colorMaskAlpha);
+        if (colorMask == 0 && !zeroColorMaskAllowed)
+        {
+            // Enable green channel, but set blending so nothing will be drawn.
+            device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+            device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+            device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+            device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+            device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+        }
+        else
+        {
+            device->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+        }
         device->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE);
 
         mMaskStateDirty = false;