// 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) {} Device::~Device() { if(device != nullptr) { driver->vkDeviceWaitIdle(device); driver->vkDestroyDevice(device, nullptr); } } bool Device::IsValid() const { return device != nullptr; } VkResult Device::CreateComputeDevice( Driver const *driver, VkInstance instance, std::unique_ptr &out) { VkResult result; // Gather all physical devices std::vector 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, nullptr, &device); if(result != VK_SUCCESS) { return result; } out.reset(new Device(driver, device, physicalDevice, static_cast(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(i); } } return -1; } std::vector Device::GetPhysicalDeviceQueueFamilyProperties( Driver const *driver, VkPhysicalDevice device) { std::vector 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 &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; } void Device::DestroyBuffer(VkBuffer buffer) const { driver->vkDestroyBuffer(device, buffer, nullptr); } VkResult Device::CreateShaderModule( const std::vector &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); } void Device::DestroyShaderModule(VkShaderModule shaderModule) const { driver->vkDestroyShaderModule(device, shaderModule, nullptr); } VkResult Device::CreateDescriptorSetLayout( const std::vector &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); } void Device::DestroyDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout) const { driver->vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); } 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); } void Device::DestroyPipelineLayout(VkPipelineLayout pipelineLayout) const { driver->vkDestroyPipelineLayout(device, pipelineLayout, nullptr); } 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); } void Device::DestroyPipeline(VkPipeline pipeline) const { driver->vkDestroyPipeline(device, pipeline, nullptr); } 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); } void Device::DestroyDescriptorPool(VkDescriptorPool descriptorPool) const { driver->vkDestroyDescriptorPool(device, descriptorPool, nullptr); } 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 &bufferInfos) const { std::vector 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, (uint32_t)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? } void Device::FreeMemory(VkDeviceMemory memory) const { driver->vkFreeMemory(device, memory, nullptr); } 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); } void Device::DestroyCommandPool(VkCommandPool commandPool) const { return driver->vkDestroyCommandPool(device, commandPool, nullptr); } 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); } void Device::FreeCommandBuffer(VkCommandPool pool, VkCommandBuffer buffer) { driver->vkFreeCommandBuffers(device, pool, 1, &buffer); } VkResult Device::BeginCommandBuffer( VkCommandBufferUsageFlags 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); }