Vulkan: Implement basic Clear and ReadPixels.

This enables the simple operations clear test on Vulkan. The current
implementation is very synchronous - it will block and finish the
current command buffer if there is any possibility of a race.

BUG=angleproject:1319

Change-Id: If01fe9a19ed6f539639a38786193d3626164cada
Reviewed-on: https://chromium-review.googlesource.com/367754
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index 87ebabd..bb8de55 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -21,6 +21,7 @@
 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
 #include "libANGLE/renderer/vulkan/TextureVk.h"
 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
+#include "libANGLE/renderer/vulkan/formatutilsvk.h"
 #include "platform/Platform.h"
 
 namespace rx
@@ -90,7 +91,8 @@
       mQueue(VK_NULL_HANDLE),
       mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
       mDevice(VK_NULL_HANDLE),
-      mCommandPool(VK_NULL_HANDLE)
+      mCommandPool(VK_NULL_HANDLE),
+      mHostVisibleMemoryIndex(std::numeric_limits<uint32_t>::max())
 {
 }
 
@@ -314,6 +316,22 @@
         ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily));
     }
 
+    VkPhysicalDeviceMemoryProperties memoryProperties;
+    vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memoryProperties);
+
+    for (uint32_t memoryIndex = 0; memoryIndex < memoryProperties.memoryTypeCount; ++memoryIndex)
+    {
+        if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &
+             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
+        {
+            mHostVisibleMemoryIndex = memoryIndex;
+            break;
+        }
+    }
+
+    ANGLE_VK_CHECK(mHostVisibleMemoryIndex < std::numeric_limits<uint32_t>::max(),
+                   VK_ERROR_INITIALIZATION_FAILED);
+
     return vk::NoError();
 }
 
@@ -555,4 +573,44 @@
     return vk::NoError();
 }
 
+vk::Error RendererVk::waitThenFinishCommandBuffer(const vk::CommandBuffer &commandBuffer,
+                                                  const vk::Semaphore &waitSemaphore)
+{
+    VkCommandBuffer commandBufferHandle = commandBuffer.getHandle();
+    VkSemaphore waitHandle              = waitSemaphore.getHandle();
+    VkPipelineStageFlags waitStageMask  = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+
+    VkSubmitInfo submitInfo;
+    submitInfo.sType                = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submitInfo.pNext                = nullptr;
+    submitInfo.waitSemaphoreCount   = 1;
+    submitInfo.pWaitSemaphores      = &waitHandle;
+    submitInfo.pWaitDstStageMask    = &waitStageMask;
+    submitInfo.commandBufferCount   = 1;
+    submitInfo.pCommandBuffers      = &commandBufferHandle;
+    submitInfo.signalSemaphoreCount = 0;
+    submitInfo.pSignalSemaphores    = nullptr;
+
+    // TODO(jmadill): Investigate how to properly queue command buffer work.
+    ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, VK_NULL_HANDLE));
+
+    // Wait indefinitely for the queue to finish.
+    ANGLE_VK_TRY(vkQueueWaitIdle(mQueue));
+
+    return vk::NoError();
+}
+
+vk::ErrorOrResult<vk::StagingImage> RendererVk::createStagingImage(TextureDimension dimension,
+                                                                   const vk::Format &format,
+                                                                   const gl::Extents &extent)
+{
+    ASSERT(mHostVisibleMemoryIndex != std::numeric_limits<uint32_t>::max());
+
+    vk::StagingImage stagingImage(mDevice);
+    ANGLE_TRY(stagingImage.init(mCurrentQueueFamilyIndex, mHostVisibleMemoryIndex, dimension,
+                                format.native, extent));
+
+    return std::move(stagingImage);
+}
+
 }  // namespace rx