Add ClearTest

Clear the screen with solid color.

BUG=chromium:936705
TEST=./vkbench -t Clear & check the output ppm file

Change-Id: I226dc6ead332b0a7a469a3a5ac618f64cbdc59a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vkbench/+/2500541
Reviewed-by: Po-Hsien Wang <pwang@chromium.org>
Commit-Queue: Po-Hsien Wang <pwang@chromium.org>
Tested-by: Po-Hsien Wang <pwang@chromium.org>
diff --git a/src/clearTest.cc b/src/clearTest.cc
new file mode 100644
index 0000000..96bf4f5
--- /dev/null
+++ b/src/clearTest.cc
@@ -0,0 +1,118 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "clearTest.h"
+
+namespace vkbench {
+void ClearTest::Initialize() {
+  CreateRenderPass();
+  CreateFrameBuffers();
+
+  // Create a cmdBuffer with draw call.
+  cmd_buffers_ = vk->GetDevice().allocateCommandBuffers(
+      {vk->GetCommandPool(), vk::CommandBufferLevel::ePrimary, 1});
+  for (const auto& buffer : cmd_buffers_) {
+    buffer.begin({});
+    vk::RenderPassBeginInfo render_pass_info;
+    render_pass_info.setFramebuffer(frame_buffer_)
+        .setRenderPass(render_pass_)
+        .setClearValueCount(1)
+        .setPClearValues(&clear_color_)
+        .setRenderArea(vk::Rect2D({}, img_size_));
+    buffer.beginRenderPass(render_pass_info, vk::SubpassContents::eInline);
+    buffer.endRenderPass();
+    buffer.end();
+  }
+
+  vk::SubmitInfo info;
+  info.setCommandBufferCount(1).setPCommandBuffers(cmd_buffers_.data());
+  smt_infos_.push_back(info);
+}
+
+void ClearTest::Run() {
+  vk->GetGFXQueue().submit(smt_infos_, {});
+  vk->GetGFXQueue().waitIdle();
+}
+
+void ClearTest::Destroy() {
+  vk::Device device = vk->GetDevice();
+  device.destroyImageView(img_view_);
+  delete img_;
+
+  device.destroyFramebuffer(frame_buffer_);
+  device.destroyRenderPass(render_pass_);
+  device.freeCommandBuffers(vk->GetCommandPool(), cmd_buffers_);
+}
+
+void ClearTest::CreateRenderPass() {
+  vk::AttachmentDescription att_description;
+  att_description.setSamples(vk::SampleCountFlagBits::e1)
+      .setFormat(img_format_)
+      .setLoadOp(vk::AttachmentLoadOp::eClear)
+      .setStoreOp(vk::AttachmentStoreOp::eStore)
+      .setInitialLayout(vk::ImageLayout::eUndefined)
+      .setFinalLayout(vk::ImageLayout::eGeneral);
+
+  vk::AttachmentReference att_reference;
+  att_reference.setAttachment(0).setLayout(
+      vk::ImageLayout::eColorAttachmentOptimal);
+  vk::SubpassDescription subpass;
+  subpass.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
+      .setColorAttachmentCount(1)
+      .setPColorAttachments(&att_reference);
+
+  vk::RenderPassCreateInfo render_pass_info;
+  render_pass_info.setAttachmentCount(1)
+      .setPAttachments(&att_description)
+      .setSubpassCount(1)
+      .setPSubpasses(&subpass);
+  render_pass_ = vk->GetDevice().createRenderPass(render_pass_info);
+}
+
+void ClearTest::CreateFrameBuffers() {
+  const vk::Device device = vk->GetDevice();
+
+  img_ = vk->AllocateImage(img_size_, img_format_,
+                           vk::ImageUsageFlagBits::eColorAttachment |
+                               vk::ImageUsageFlagBits::eTransferSrc,
+                           vk::MemoryPropertyFlagBits::eDeviceLocal);
+
+  vk::ImageViewCreateInfo img_view_create_info;
+  img_view_create_info.setViewType(vk::ImageViewType::e2D)
+      .setFormat(img_format_)
+      .setImage(img_->GetImage());
+  img_view_create_info.subresourceRange
+      .setAspectMask(vk::ImageAspectFlagBits::eColor)
+      .setBaseMipLevel(0)
+      .setLevelCount(1)
+      .setBaseArrayLayer(0)
+      .setLayerCount(1);
+  img_view_ = device.createImageView(img_view_create_info);
+
+  vk::FramebufferCreateInfo frame_buffer_info;
+  frame_buffer_info.setRenderPass(render_pass_)
+      .setAttachmentCount(1)
+      .setPAttachments(&img_view_)
+      .setWidth(img_size_.width)
+      .setHeight(img_size_.height)
+      .setLayers(1);
+  frame_buffer_ = device.createFramebuffer(frame_buffer_info);
+}
+
+void ClearTest::SaveImage(std::string filename) const {
+  const vk::Device device = vk->GetDevice();
+  vkImage* dest = vk->GetReadableImage(img_, img_size_, img_format_);
+  DEFER(delete dest);
+  vk::SubresourceLayout sub_resource_layout = device.getImageSubresourceLayout(
+      dest->GetImage(), {vk::ImageAspectFlagBits::eColor, 0, 0});
+  const char* data =
+      (const char*)device.mapMemory(dest->GetMemory(), 0, VK_WHOLE_SIZE);
+  data += sub_resource_layout.offset;
+  SavePPM(filename, data, img_size_.width, img_size_.height,
+          sub_resource_layout.rowPitch);
+
+  DEBUG("Saved image to %s", filename.c_str());
+}
+
+}  // namespace vkbench
diff --git a/src/clearTest.h b/src/clearTest.h
new file mode 100644
index 0000000..124c69e
--- /dev/null
+++ b/src/clearTest.h
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VKBENCH_CLEARTEST_H
+#define VKBENCH_CLEARTEST_H
+
+#include "testBase.h"
+
+namespace vkbench {
+class ClearTest : public testBase {
+ public:
+  ClearTest(vkBase* base) {
+    vk = base;
+    clear_color_.setColor({std::array<float, 4>{0.f, 0.f, 1.f}});  // Blue
+    snprintf(name_, 100, "ClearTest");
+    snprintf(desp_, 1024, "Time to clear window to specific color.");
+  }
+  ~ClearTest() override = default;
+
+  const char* Name() const override { return name_; }
+  const char* Desp() const override { return desp_; }
+  const char* Unit() const override { return "mpixels_sec"; }
+  virtual double FormatMeasurement(double time) override {
+    return img_size_.width * img_size_.height / time;
+  }
+  void SaveImage(std::string filename) const override;
+
+ protected:
+  void Initialize() override;
+  void Run() override;
+  void Destroy() override;
+
+ private:
+  void CreateRenderPass();
+  void CreateFrameBuffers();
+
+  char name_[100];
+  char desp_[1024];
+  vk::ClearValue clear_color_;
+  std::vector<vk::SubmitInfo> smt_infos_;
+  std::vector<vk::CommandBuffer> cmd_buffers_;
+  vk::Extent2D img_size_{256, 256};
+  vk::Format img_format_ = vk::Format::eR8G8B8A8Unorm;
+
+  vk::RenderPass render_pass_;
+  vk::Framebuffer frame_buffer_;
+  vkImage* img_;
+  vk::ImageView img_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClearTest);
+};
+}  // namespace vkbench
+#endif  // VKBENCH_CLEARTEST_H
diff --git a/src/main.cc b/src/main.cc
index 2bf9b40..29a0543 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -9,6 +9,7 @@
 #include <map>
 #include <vector>
 
+#include "clearTest.h"
 #include "constant.h"
 #include "drawSizeTest.h"
 #include "submitTest.h"
@@ -183,6 +184,7 @@
       new vkbench::DrawSizeTest(128, &simpleVulkan),
       new vkbench::DrawSizeTest(512, &simpleVulkan),
       new vkbench::DrawSizeTest(1024, &simpleVulkan),
+      new vkbench::ClearTest(&simpleVulkan),
   };
 
   // Sort to bundle tests using same vulkan instance together.