tests: Add a unit test for a simple memcpy compute shader

Bug: b/126871859
Change-Id: I0b3db6c033419a2ad54453d470960330d4f337cc
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/25909
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/tests/VulkanUnitTests/Device.cpp b/tests/VulkanUnitTests/Device.cpp
new file mode 100644
index 0000000..1fcc8b8
--- /dev/null
+++ b/tests/VulkanUnitTests/Device.cpp
@@ -0,0 +1,397 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Device.hpp"
+#include "Driver.hpp"
+
+Device::Device()
+		: driver(nullptr),
+		  device(nullptr),
+		  physicalDevice(nullptr),
+		  queueFamilyIndex(0) {}
+
+Device::Device(
+		Driver const *driver, VkDevice device, VkPhysicalDevice physicalDevice,
+		uint32_t queueFamilyIndex)
+	: driver(driver),
+	  device(device),
+	  physicalDevice(physicalDevice),
+	  queueFamilyIndex(queueFamilyIndex) {}
+
+bool Device::IsValid() const { return device != nullptr; }
+
+VkResult Device::CreateComputeDevice(
+		Driver const *driver, VkInstance instance, Device *out)
+{
+    VkResult result;
+
+    // Gather all physical devices
+    std::vector<VkPhysicalDevice> physicalDevices;
+    result = GetPhysicalDevices(driver, instance, physicalDevices);
+    if (result != VK_SUCCESS)
+    {
+		return result;
+    }
+
+    // Inspect each physical device's queue families for compute support.
+    for (auto physicalDevice : physicalDevices)
+    {
+        int queueFamilyIndex = GetComputeQueueFamilyIndex(driver, physicalDevice);
+        if (queueFamilyIndex < 0)
+        {
+            continue;
+        }
+
+        const float queuePrioritory = 1.0f;
+        const VkDeviceQueueCreateInfo deviceQueueCreateInfo = {
+            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,  // sType
+            nullptr,                                     // pNext
+            0,                                           // flags
+            (uint32_t)queueFamilyIndex,                  // queueFamilyIndex
+            1,                                           // queueCount
+            &queuePrioritory,                            // pQueuePriorities
+        };
+
+        const VkDeviceCreateInfo deviceCreateInfo = {
+            VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,  // sType
+            nullptr,                               // pNext
+            0,                                     // flags
+            1,                                     // queueCreateInfoCount
+            &deviceQueueCreateInfo,                // pQueueCreateInfos
+            0,                                     // enabledLayerCount
+            nullptr,                               // ppEnabledLayerNames
+            0,                                     // enabledExtensionCount
+            nullptr,                               // ppEnabledExtensionNames
+            nullptr,                               // pEnabledFeatures
+        };
+
+        VkDevice device;
+        result = driver->vkCreateDevice(physicalDevice, &deviceCreateInfo, 0, &device);
+        if (result != VK_SUCCESS)
+        {
+            return result;
+        }
+
+		*out = Device(driver, device, physicalDevice, static_cast<uint32_t>(queueFamilyIndex));
+        return VK_SUCCESS;
+    }
+
+    return VK_SUCCESS;
+}
+
+int Device::GetComputeQueueFamilyIndex(
+		Driver const *driver, VkPhysicalDevice device)
+{
+    auto properties = GetPhysicalDeviceQueueFamilyProperties(driver, device);
+    for (uint32_t i = 0; i < properties.size(); i++)
+    {
+        if ((properties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0)
+        {
+            return static_cast<int>(i);
+        }
+    }
+    return -1;
+}
+
+std::vector<VkQueueFamilyProperties>
+		Device::GetPhysicalDeviceQueueFamilyProperties(
+				Driver const *driver, VkPhysicalDevice device)
+{
+    std::vector<VkQueueFamilyProperties> out;
+    uint32_t count = 0;
+    driver->vkGetPhysicalDeviceQueueFamilyProperties(device, &count, nullptr);
+    out.resize(count);
+    driver->vkGetPhysicalDeviceQueueFamilyProperties(device, &count, out.data());
+    return out;
+}
+
+VkResult Device::GetPhysicalDevices(
+		const Driver* driver, VkInstance instance,
+		std::vector<VkPhysicalDevice>& out)
+{
+    uint32_t count = 0;
+    VkResult result = driver->vkEnumeratePhysicalDevices(instance, &count, 0);
+    if (result != VK_SUCCESS)
+    {
+        return result;
+    }
+    out.resize(count);
+    return driver->vkEnumeratePhysicalDevices(instance, &count, out.data());
+}
+
+VkResult Device::CreateStorageBuffer(
+		VkDeviceMemory memory, VkDeviceSize size,
+		VkDeviceSize offset, VkBuffer* out) const
+{
+	const VkBufferCreateInfo info = {
+		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
+		nullptr,                              // pNext
+		0,                                    // flags
+		size,                                 // size
+		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,   // usage
+		VK_SHARING_MODE_EXCLUSIVE,            // sharingMode
+		0,                                    // queueFamilyIndexCount
+		nullptr,                              // pQueueFamilyIndices
+	};
+
+	VkBuffer buffer;
+	VkResult result = driver->vkCreateBuffer(device, &info, 0, &buffer);
+	if (result != VK_SUCCESS)
+	{
+		return result;
+	}
+
+	result = driver->vkBindBufferMemory(device, buffer, memory, offset);
+	if (result != VK_SUCCESS)
+	{
+		return result;
+	}
+
+	*out = buffer;
+	return VK_SUCCESS;
+}
+
+VkResult Device::CreateShaderModule(
+		const std::vector<uint32_t>& spirv, VkShaderModule* out) const
+{
+	VkShaderModuleCreateInfo info = {
+		VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType
+		nullptr,                                     // pNext
+		0,                                           // flags
+		spirv.size() * 4,                            // codeSize
+		spirv.data(),                                // pCode
+	};
+	return driver->vkCreateShaderModule(device, &info, 0, out);
+}
+
+VkResult Device::CreateDescriptorSetLayout(
+		const std::vector<VkDescriptorSetLayoutBinding>& bindings,
+		VkDescriptorSetLayout* out) const
+{
+	VkDescriptorSetLayoutCreateInfo info = {
+		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType
+		nullptr,                                             // pNext
+		0,                                                   // flags
+		(uint32_t)bindings.size(),                           // bindingCount
+		bindings.data(),                                     // pBindings
+	};
+
+	return driver->vkCreateDescriptorSetLayout(device, &info, 0, out);
+}
+
+VkResult Device::CreatePipelineLayout(
+		VkDescriptorSetLayout layout, VkPipelineLayout* out) const
+{
+	VkPipelineLayoutCreateInfo info = {
+		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
+		nullptr,                                       // pNext
+		0,                                             // flags
+		1,                                             // setLayoutCount
+		&layout,                                       // pSetLayouts
+		0,                                             // pushConstantRangeCount
+		nullptr,                                       // pPushConstantRanges
+	};
+
+	return driver->vkCreatePipelineLayout(device, &info, 0, out);
+}
+
+VkResult Device::CreateComputePipeline(
+		VkShaderModule module, VkPipelineLayout pipelineLayout,
+		VkPipeline* out) const
+{
+	VkComputePipelineCreateInfo info = {
+		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // sType
+		nullptr,                                        // pNext
+		0,                                              // flags
+		{
+			// stage
+			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
+			nullptr,                                             // pNext
+			0,                                                   // flags
+			VK_SHADER_STAGE_COMPUTE_BIT,                         // stage
+			module,                                              // module
+			"main",                                              // pName
+			nullptr,                                             // pSpecializationInfo
+		},
+		pipelineLayout, // layout
+		0,              // basePipelineHandle
+		0,              // basePipelineIndex
+	};
+
+	return driver->vkCreateComputePipelines(device, 0, 1, &info, 0, out);
+}
+
+VkResult Device::CreateStorageBufferDescriptorPool(uint32_t descriptorCount,
+		VkDescriptorPool* out) const
+{
+	VkDescriptorPoolSize size = {
+		VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // type
+		descriptorCount,                   // descriptorCount
+	};
+
+	VkDescriptorPoolCreateInfo info = {
+		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // sType
+		nullptr,                                       // pNext
+		0,                                             // flags
+		1,                                             // maxSets
+		1,                                             // poolSizeCount
+		&size,                                         // pPoolSizes
+	};
+
+	return driver->vkCreateDescriptorPool(device, &info, 0, out);
+}
+
+VkResult Device::AllocateDescriptorSet(
+		VkDescriptorPool pool, VkDescriptorSetLayout layout,
+		VkDescriptorSet* out) const
+{
+	VkDescriptorSetAllocateInfo info = {
+		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // sType
+		nullptr,                                        // pNext
+		pool,                                           // descriptorPool
+		1,                                              // descriptorSetCount
+		&layout,                                        // pSetLayouts
+	};
+
+	return driver->vkAllocateDescriptorSets(device, &info, out);
+}
+
+void Device::UpdateStorageBufferDescriptorSets(
+		VkDescriptorSet descriptorSet,
+		const std::vector<VkDescriptorBufferInfo>& bufferInfos) const
+{
+	std::vector<VkWriteDescriptorSet> writes;
+	writes.reserve(bufferInfos.size());
+	for (uint32_t i = 0; i < bufferInfos.size(); i++)
+	{
+		writes.push_back(VkWriteDescriptorSet{
+			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+			nullptr,                                // pNext
+			descriptorSet,                          // dstSet
+			i,                                      // dstBinding
+			0,                                      // dstArrayElement
+			1,                                      // descriptorCount
+			VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,      // descriptorType
+			nullptr,                                // pImageInfo
+			&bufferInfos[i],                        // pBufferInfo
+			nullptr,                                // pTexelBufferView
+		});
+	}
+
+	driver->vkUpdateDescriptorSets(device, writes.size(), writes.data(), 0, nullptr);
+}
+
+VkResult Device::AllocateMemory(size_t size, VkMemoryPropertyFlags flags, VkDeviceMemory* out) const
+{
+	VkPhysicalDeviceMemoryProperties properties;
+	driver->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties);
+
+	for(uint32_t type = 0; type < properties.memoryTypeCount; type++)
+	{
+		if ((flags & properties.memoryTypes[type].propertyFlags) == 0)
+		{
+			continue;  // Type mismatch
+		}
+
+		if (size > properties.memoryHeaps[properties.memoryTypes[type].heapIndex].size)
+		{
+			continue;  // Too small.
+		}
+
+		const VkMemoryAllocateInfo info = {
+			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,  // sType
+			nullptr,                                 // pNext
+			size,                                    // allocationSize
+			type,                                    // memoryTypeIndex
+		};
+
+		return driver->vkAllocateMemory(device, &info, 0, out);
+	}
+
+    return VK_ERROR_OUT_OF_DEVICE_MEMORY; // TODO: Change to something not made up?
+}
+
+VkResult Device::MapMemory(VkDeviceMemory memory, VkDeviceSize offset,
+		VkDeviceSize size, VkMemoryMapFlags flags, void **ppData) const
+{
+	return driver->vkMapMemory(device, memory, offset, size, flags, ppData);
+}
+
+void Device::UnmapMemory(VkDeviceMemory memory) const
+{
+	driver->vkUnmapMemory(device, memory);
+}
+
+VkResult Device::CreateCommandPool(VkCommandPool* out) const
+{
+    VkCommandPoolCreateInfo info = {
+        VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,  // sType
+        nullptr,                                     // pNext
+        0,                                           // flags
+        queueFamilyIndex,                            // queueFamilyIndex
+    };
+    return driver->vkCreateCommandPool(device, &info, 0, out);
+}
+
+VkResult Device::AllocateCommandBuffer(
+		VkCommandPool pool, VkCommandBuffer* out) const
+{
+    VkCommandBufferAllocateInfo info = {
+        VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,  // sType
+        nullptr,                                         // pNext
+        pool,                                            // commandPool
+        VK_COMMAND_BUFFER_LEVEL_PRIMARY,                 // level
+        1,                                               // commandBufferCount
+    };
+    return driver->vkAllocateCommandBuffers(device, &info, out);
+}
+
+VkResult Device::BeginCommandBuffer(
+		VkCommandBufferUsageFlagBits usage, VkCommandBuffer commandBuffer) const
+{
+    VkCommandBufferBeginInfo info = {
+        VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,  // sType
+        nullptr,                                      // pNext
+        usage,                                        // flags
+        nullptr,                                      // pInheritanceInfo
+    };
+
+    return driver->vkBeginCommandBuffer(commandBuffer, &info);
+}
+
+VkResult Device::QueueSubmitAndWait(VkCommandBuffer commandBuffer) const
+{
+    VkQueue queue;
+    driver->vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue);
+
+    VkSubmitInfo info = {
+        VK_STRUCTURE_TYPE_SUBMIT_INFO,  // sType
+        nullptr,                        // pNext
+        0,                              // waitSemaphoreCount
+        nullptr,                        // pWaitSemaphores
+        nullptr,                        // pWaitDstStageMask
+        1,                              // commandBufferCount
+        &commandBuffer,                 // pCommandBuffers
+        0,                              // signalSemaphoreCount
+        nullptr,                        // pSignalSemaphores
+    };
+
+    VkResult result = driver->vkQueueSubmit(queue, 1, &info, 0);
+    if (result != VK_SUCCESS)
+    {
+        return result;
+    }
+
+    return driver->vkQueueWaitIdle(queue);
+}