Vulkan: Handle dirty RTs with state messages.

Prior to this CL we were handling dirty state change notifications by
flushing the RT Images just prior to use or just after they were
changed. This could lead to a few redundant checks in several places.
It also meant we needed an owner pointer from the RT to the parent
Image. This pointer would be null for Surfaces and Renderbuffers.

This cleans up the image flushing logic to be handled by dirty bit
notifications. When an app updates an attached Texture with TexSubImage
or related calls it will send a notification to the Framebuffer. The
Framebuffer then sets a dirty contents bit that is handled in the
implementation. In Vulkan this means flushing the dirty bits.

Requires adding a flag to the FramebufferImpl class to determine if we
need to syncState before we checkStatus. Adding the option allows us to
only call syncState for the GL back-end. Not calling syncState allows
the robust resource init operation to happen *before* we syncState.
Which in turn allows FramebuffeVk to initialize the VkImages in one go.

Added new regression tests for Texture updates. This might not cover
all cases. I found it was very hard to trigger some of the resource
update staging in TextureVk.

Bug: angleproject:3427
Change-Id: Idfa177436ba7fcb9d398f2b67922e085f778f82a
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1601552
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 652bcfd..19f8a65 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -968,11 +968,16 @@
 
     if (mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE)
     {
-        angle::Result err = syncState(context);
-        if (err != angle::Result::Continue)
+        // We can skip syncState on several back-ends.
+        if (mImpl->shouldSyncStateBeforeCheckStatus())
         {
-            return 0;
+            angle::Result err = syncState(context);
+            if (err != angle::Result::Continue)
+            {
+                return 0;
+            }
         }
+
         if (!mImpl->checkStatus(context))
         {
             mCachedStatus = GL_FRAMEBUFFER_UNSUPPORTED;
@@ -1848,6 +1853,14 @@
 {
     if (message != angle::SubjectMessage::SubjectChanged)
     {
+        // This can be triggered by SubImage calls for Textures.
+        if (message == angle::SubjectMessage::ContentsChanged)
+        {
+            mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 + index);
+            onStateChange(context, angle::SubjectMessage::DirtyBitsFlagged);
+            return;
+        }
+
         // This can be triggered by the GL back-end TextureGL class.
         ASSERT(message == angle::SubjectMessage::DirtyBitsFlagged);
         return;