Exemplo n.º 1
0
VkPhysicalDeviceMemoryProperties PhysicalDevice::memory_properties() const {
    VkPhysicalDeviceMemoryProperties info;

    vkGetPhysicalDeviceMemoryProperties(handle(), &info);

    return info;
}
Exemplo n.º 2
0
rhi::IDevice::Result
Device::Create(rhi::IDeviceAdapter* pAdapter, bool withDbg)
{
	m_pGpu = static_cast<DeviceAdapter*>(pAdapter)->m_pGpu;
	VkPhysicalDevice& Gpu = *static_cast<DeviceAdapter*>(pAdapter)->m_pGpu;
	vkGetPhysicalDeviceMemoryProperties(Gpu, &m_MemoryProperties);
	VkResult err = CreateDevice(Gpu, withDbg, &m_Device);
	if (err)
	{
		VKLOG(Fatal, "Device-Create: Could not create Vulkan Device : %s.", ErrorString(err).c_str());
		return rhi::IDevice::DeviceNotFound;
	}
	else 
	{
		LoadVulkan(RHIRoot::GetInstance(), m_Device);
#if K3DPLATFORM_OS_WIN && _DEBUG
		if (withDbg)
		{
			SetupDebugging(RHIRoot::GetInstance(), VK_DEBUG_REPORT_ERROR_BIT_EXT |
				VK_DEBUG_REPORT_WARNING_BIT_EXT |
				VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, nullptr);
		}
#endif
		m_ResourceManager = std::make_unique<ResourceManager>(this, 1024, 1024);
		m_ContextPool = std::make_unique<CommandContextPool>(this);
		InitCmdQueue(VK_QUEUE_GRAPHICS_BIT, m_GfxQueueIndex, 0);
		return rhi::IDevice::DeviceFound;
	}
}
Exemplo n.º 3
0
void GpuMemoryManager::init(VkPhysicalDevice pdev, VkDevice dev, GrAllocator<U8> alloc)
{
	ANKI_ASSERT(pdev);
	ANKI_ASSERT(dev);

	// Print some info
	for(const ClassInf& c : CLASSES)
	{
		ANKI_LOGI("VK: GPU mem class. Chunk size: %u, slotSize: %u, allocsPerChunk %u",
			c.m_chunkSize,
			c.m_slotSize,
			c.m_chunkSize / c.m_slotSize);
	}

	vkGetPhysicalDeviceMemoryProperties(pdev, &m_memoryProperties);

	m_alloc = alloc;

	m_ifaces.create(alloc, m_memoryProperties.memoryTypeCount);
	for(U i = 0; i < m_ifaces.getSize(); ++i)
	{
		Interface& iface = m_ifaces[i];

		iface.m_alloc = alloc;
		iface.m_dev = dev;
		iface.m_memTypeIdx = i;
	}

	// One allocator per type per linear/non-linear resources
	m_callocs.create(alloc, m_memoryProperties.memoryTypeCount * 2);
	for(U i = 0; i < m_callocs.getSize(); ++i)
	{
		m_callocs[i].init(m_alloc, &m_ifaces[i / 2]);
	}
}
static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
    VkPhysicalDeviceMemoryProperties prop;
    vkGetPhysicalDeviceMemoryProperties(g_Gpu, &prop);
    for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
        if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<<i))
            return i;
    return 0xffffffff; // Unable to find memoryType
}
Exemplo n.º 5
0
Device::Device(VkPhysicalDevice physicalDevice) : physicalDevice(physicalDevice)
{
    // select a queue family with compute support
    uint32_t numQueues;
    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, nullptr);

    VkQueueFamilyProperties *queueFamilyProperties = new VkQueueFamilyProperties[numQueues];
    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueues, queueFamilyProperties);

    for (uint32_t i = 0; i < numQueues; i++) {
        if (queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
            computeQueueFamily = i;
            break;
        }
    }

    delete [] queueFamilyProperties;
    if (computeQueueFamily == -1) {
        throw ERROR_DEVICES;
    }

    VkDeviceQueueCreateInfo queueCreateInfo = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
    queueCreateInfo.queueCount = 1;
    float priorities[] = {1.0f};
    queueCreateInfo.pQueuePriorities = priorities;
    queueCreateInfo.queueFamilyIndex = computeQueueFamily;

    // create the logical device
    VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
    VkDeviceCreateInfo deviceCreateInfo = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
    deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
    deviceCreateInfo.pEnabledFeatures = &physicalDeviceFeatures;
    deviceCreateInfo.queueCreateInfoCount = 1;
    if (VK_SUCCESS != vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device)) {
        throw ERROR_DEVICES;
    }

    vkGetDeviceQueue(device, computeQueueFamily, 0, &queue);
    vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);

    // get indices of memory types we care about
    VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties;
    vkGetPhysicalDeviceMemoryProperties(physicalDevice, &physicalDeviceMemoryProperties);
    for (uint32_t i = 0; i < physicalDeviceMemoryProperties.memoryTypeCount; i++) {
        if (physicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT && memoryTypeMappable == -1) {
            memoryTypeMappable = i;
        }

        if (physicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT && memoryTypeLocal == -1) {
            memoryTypeLocal = i;
        }
    }

    // create the implicit command buffer
    implicitCommandBuffer = new CommandBuffer(*this);
}
Exemplo n.º 6
0
uint32_t VkApp::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties){
	VkPhysicalDeviceMemoryProperties memProperties;
	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);

	for( uint32_t i = 0; i < memProperties.memoryTypeCount; ++i ){
		if( (typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties ){
			return i;
		}
	}
	throw std::runtime_error("failed to find suitable memory type!");
}
Exemplo n.º 7
0
Error GrManagerImpl::initMemory(const ConfigSet& cfg)
{
	vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &m_memoryProperties);

	m_gpuMemManager.init(m_physicalDevice, m_device, getAllocator());

	// Transient mem
	ANKI_CHECK(m_transientMem.init(cfg));

	return ErrorCode::NONE;
}
Exemplo n.º 8
0
	memory_type_mapping get_memory_mapping(const vk::physical_device& dev)
	{
		VkPhysicalDevice pdev = dev;
		VkPhysicalDeviceMemoryProperties memory_properties;
		vkGetPhysicalDeviceMemoryProperties(pdev, &memory_properties);

		memory_type_mapping result;
		result.device_local = VK_MAX_MEMORY_TYPES;
		result.host_visible_coherent = VK_MAX_MEMORY_TYPES;

		bool host_visible_cached = false;
		VkDeviceSize  host_visible_vram_size = 0;
		VkDeviceSize  device_local_vram_size = 0;

		for (u32 i = 0; i < memory_properties.memoryTypeCount; i++)
		{
			VkMemoryHeap &heap = memory_properties.memoryHeaps[memory_properties.memoryTypes[i].heapIndex];

			bool is_device_local = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
			if (is_device_local)
			{
				if (device_local_vram_size < heap.size)
				{
					result.device_local = i;
					device_local_vram_size = heap.size;
				}
			}

			bool is_host_visible = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
			bool is_host_coherent = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
			bool is_cached = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT);

			if (is_host_coherent && is_host_visible)
			{
				if ((is_cached && !host_visible_cached) ||
					(host_visible_vram_size < heap.size))
				{
					result.host_visible_coherent = i;
					host_visible_vram_size = heap.size;
					host_visible_cached = is_cached;
				}
			}
		}

		if (result.device_local == VK_MAX_MEMORY_TYPES) fmt::throw_exception("GPU doesn't support device local memory" HERE);
		if (result.host_visible_coherent == VK_MAX_MEMORY_TYPES) fmt::throw_exception("GPU doesn't support host coherent device local memory" HERE);
		return result;
	}
Exemplo n.º 9
0
uint32_t VkHelper::findMemoryType(const VkPhysicalDevice physicalDevice, const VkMemoryRequirements& memReqs, VkMemoryPropertyFlags reqFlags, VkMemoryPropertyFlags prefFlags)
{
	VkPhysicalDeviceMemoryProperties memProps;
	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);

	uint32_t selectedType = ~0u;
	uint32_t memType;

	for (memType = 0; memType < memProps.memoryTypeCount; ++memType)
	{
		if (memReqs.memoryTypeBits & (1 << memType))
		{
			const VkMemoryType& type = memProps.memoryTypes[memType];

			if ((type.propertyFlags & prefFlags) == prefFlags)
			{
				selectedType = memType;
				break;
			}
		}
	}

	if (selectedType == ~0u)
	{
		for (memType = 0; memType < memProps.memoryTypeCount; ++memType)
		{
			if (memReqs.memoryTypeBits & (1 << memType))
			{
				const VkMemoryType& type = memProps.memoryTypes[memType];

				if ((type.propertyFlags & reqFlags) == reqFlags)
				{
					selectedType = memType;
					break;
				}
			}
		}
	}

	if (selectedType == ~0u)
	{
		std::runtime_error("ERROR: required memory type is not found!");
	}

	return selectedType;
}
Exemplo n.º 10
0
VulkanContext::VulkanContext(VkInstance instance, VkPhysicalDevice physical_device)
    : m_instance(instance), m_physical_device(physical_device)
{
  // Read device physical memory properties, we need it for allocating buffers
  vkGetPhysicalDeviceProperties(physical_device, &m_device_properties);
  vkGetPhysicalDeviceMemoryProperties(physical_device, &m_device_memory_properties);

  // Would any drivers be this silly? I hope not...
  m_device_properties.limits.minUniformBufferOffsetAlignment = std::max(
      m_device_properties.limits.minUniformBufferOffsetAlignment, static_cast<VkDeviceSize>(1));
  m_device_properties.limits.minTexelBufferOffsetAlignment = std::max(
      m_device_properties.limits.minTexelBufferOffsetAlignment, static_cast<VkDeviceSize>(1));
  m_device_properties.limits.optimalBufferCopyOffsetAlignment = std::max(
      m_device_properties.limits.optimalBufferCopyOffsetAlignment, static_cast<VkDeviceSize>(1));
  m_device_properties.limits.optimalBufferCopyRowPitchAlignment = std::max(
      m_device_properties.limits.optimalBufferCopyRowPitchAlignment, static_cast<VkDeviceSize>(1));
}
Exemplo n.º 11
0
// Devices
void Renderer::_InitDevice() {
	{
		uint32_t gpu_count = 0;
		
		// Read number of GPU's
		vkEnumeratePhysicalDevices(_instance, &gpu_count, nullptr);
		
		std::vector<VkPhysicalDevice> gpu_list(gpu_count);

		// Populate list
		vkEnumeratePhysicalDevices(_instance, &gpu_count, gpu_list.data());

		_gpu = gpu_list[0]; // Get the first available list
		vkGetPhysicalDeviceProperties(_gpu, &_gpu_properties);
		vkGetPhysicalDeviceMemoryProperties(_gpu, &_gpu_memory_properties);
	}
	
	{
		uint32_t family_count = 0;

		// Read number of GPU queue family properties
		vkGetPhysicalDeviceQueueFamilyProperties(_gpu, &family_count, nullptr);

		std::vector<VkQueueFamilyProperties> family_property_list(family_count);

		// Populate list
		vkGetPhysicalDeviceQueueFamilyProperties(_gpu, &family_count, family_property_list.data());
		
		// Find the graphics family
		bool found = false;
		for (uint32_t i = 0; i < family_count; ++i) {
			if (family_property_list[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
				found = true;
				_graphics_family_index = i;
			}
		}

		if (!found) {
			assert(0 && "Vulkan ERROR: Queue family supporting graphics not found.");
			std::exit(-1);
		}
	}

	// Instance Layers
	{
		uint32_t layer_count = 0;

		// Read the number of layers
		vkEnumerateInstanceLayerProperties(&layer_count, nullptr);

		std::vector<VkLayerProperties> layer_property_list(layer_count);

		// Populate list
		vkEnumerateInstanceLayerProperties(&layer_count, layer_property_list.data());

#if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG
		std::cout << "Instance layers: \n";
		for (auto &i : layer_property_list) {
			std::cout << " " << i.layerName << "\t\t | " << i.description << std::endl;
		}
		std::cout << std::endl;
#endif
	}

	// Instance Extensions
	{
		uint32_t extension_count = 0;

		// Read the number of extensions
		vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);

		std::vector<VkExtensionProperties> extension_property_list(extension_count);

		// Populate list
		vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_property_list.data());

#if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG
		std::cout << "Instance extensions: \n";
		for (auto &i : extension_property_list) {
			std::cout << " " << i.extensionName << "\t\t | " << i.specVersion << std::endl;
		}
		std::cout << std::endl;
#endif
	}

	// Device Layers
	{
		uint32_t layer_count = 0;

		// Read the number of layers
		vkEnumerateDeviceLayerProperties(_gpu, &layer_count, nullptr);

		std::vector<VkLayerProperties> layer_property_list(layer_count);

		// Populate list
		vkEnumerateDeviceLayerProperties(_gpu, &layer_count, layer_property_list.data());

#if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG
		std::cout << "Device layers: \n";
		for (auto &i : layer_property_list) {
			std::cout << " " << i.layerName << "\t\t | " << i.description << std::endl;
		}
		std::cout << std::endl;
#endif
	}

	// Device Extensions
	{
		uint32_t extension_count = 0;

		// Read the number of extensions
		vkEnumerateDeviceExtensionProperties(_gpu, nullptr, &extension_count, nullptr);

		std::vector<VkExtensionProperties> extension_property_list(extension_count);

		// Populate list
		vkEnumerateDeviceExtensionProperties(_gpu, nullptr, &extension_count, extension_property_list.data());

#if BUILD_ENABLE_VULKAN_RUNTIME_DEBUG
		std::cout << "Device extensions: \n";
		for (auto &i : extension_property_list) {
			std::cout << " " << i.extensionName << "\t\t | " << i.specVersion << std::endl;
		}
		std::cout << std::endl;
#endif
	}

	float queue_priorities[] {1.0f};

	VkDeviceQueueCreateInfo device_queue_create_info {};
	device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
	device_queue_create_info.queueFamilyIndex = _graphics_family_index;
	device_queue_create_info.queueCount = 1;
	device_queue_create_info.pQueuePriorities = queue_priorities;

	VkDeviceCreateInfo device_create_info = {};
	device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
	device_create_info.queueCreateInfoCount = 1;
	device_create_info.pQueueCreateInfos = &device_queue_create_info;
	device_create_info.enabledLayerCount = (uint32_t) _device_layer_list.size();
	device_create_info.ppEnabledLayerNames = _device_layer_list.data();
	device_create_info.enabledExtensionCount = (uint32_t) _device_extension_list.size();
	device_create_info.ppEnabledExtensionNames = _device_extension_list.data();

	ErrorCheck(vkCreateDevice(_gpu, &device_create_info, nullptr, &_device));

	vkGetDeviceQueue(_device, _graphics_family_index, 0, &_queue);
}
Exemplo n.º 12
0
bool create_device() {
    uint32_t num_devices = 0;
    VK_VERIFY (vkEnumeratePhysicalDevices(vk_globals::instance, &num_devices, nullptr));
    VERIFY_LOG (num_devices > 0, LOG_TYPE, "Error occurred during physical devices enumeration!", "");

    std::vector<VkPhysicalDevice> physical_devices(num_devices);
    VK_VERIFY(vkEnumeratePhysicalDevices(vk_globals::instance, &num_devices, &physical_devices[0]));

    uint32_t selected_graphics_queue_family_index = UINT32_MAX;
    uint32_t selected_present_queue_family_index = UINT32_MAX;
    std::vector<const char *> extensions = {
        VK_KHR_SWAPCHAIN_EXTENSION_NAME
    };

    for (uint32_t i = 0; i < num_devices; ++i) {
        if (check_physical_device_properties(physical_devices[i],
                                             selected_graphics_queue_family_index,
                                             selected_present_queue_family_index,
                                             extensions)) {
            vk_globals::gpu = physical_devices[i];
        }
    }

    VERIFY_LOG (vk_globals::gpu != nullptr, LOG_TYPE,
                "Could not select physical device based on the chosen properties!", "");

    vkGetPhysicalDeviceMemoryProperties(vk_globals::gpu, &vk_globals::gpu_memory_properties);

    std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
    std::vector<float> queue_priorities = {1.0f};

    queue_create_infos.push_back(
        {
            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,       // VkStructureType              sType
            nullptr,                                          // const void                  *pNext
            0,                                                // VkDeviceQueueCreateFlags     flags
            selected_graphics_queue_family_index,             // uint32_t                     queueFamilyIndex
            static_cast<uint32_t>(queue_priorities.size()),   // uint32_t                     queueCount
            &queue_priorities[0]                              // const float                 *pQueuePriorities
        }
    );

    if (selected_graphics_queue_family_index != selected_present_queue_family_index) {
        queue_create_infos.push_back(
            {
                VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,     // VkStructureType              sType
                nullptr,                                        // const void                  *pNext
                0,                                              // VkDeviceQueueCreateFlags     flags
                selected_present_queue_family_index,            // uint32_t                     queueFamilyIndex
                static_cast<uint32_t>(queue_priorities.size()), // uint32_t                     queueCount
                &queue_priorities[0]                            // const float                 *pQueuePriorities
            }
        );
    }

    VkDeviceCreateInfo device_create_info = {
        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,             // VkStructureType                    sType
        nullptr,                                          // const void                        *pNext
        0,                                                // VkDeviceCreateFlags                flags
        static_cast<uint32_t>(queue_create_infos.size()), // uint32_t                           queueCreateInfoCount
        &queue_create_infos[0],                           // const VkDeviceQueueCreateInfo     *pQueueCreateInfos
        0,                                                // uint32_t                           enabledLayerCount
        nullptr,                                          // const char * const                *ppEnabledLayerNames
        static_cast<uint32_t>(extensions.size()),         // uint32_t                           enabledExtensionCount
        &extensions[0],                                   // const char * const                *ppEnabledExtensionNames
        nullptr                                           // const VkPhysicalDeviceFeatures    *pEnabledFeatures
    };

    VK_VERIFY (vkCreateDevice(vk_globals::gpu, &device_create_info, nullptr, &(vk_globals::device)));

    vk_globals::graphics_queue.index = selected_graphics_queue_family_index;
    vk_globals::present_queue.index = selected_present_queue_family_index;

    return true;
}
Exemplo n.º 13
0
gboolean
gst_vulkan_device_open (GstVulkanDevice * device, GError ** error)
{
  const char *extension_names[64];
  uint32_t enabled_extension_count = 0;
  uint32_t device_extension_count = 0;
  VkExtensionProperties *device_extensions = NULL;
  uint32_t enabled_layer_count = 0;
  gchar **enabled_layers;
  uint32_t device_layer_count = 0;
  VkLayerProperties *device_layers;
  gboolean have_swapchain_ext;
  VkPhysicalDevice gpu;
  VkResult err;
  guint i;

  g_return_val_if_fail (GST_IS_VULKAN_DEVICE (device), FALSE);

  GST_OBJECT_LOCK (device);

  if (device->priv->opened) {
    GST_OBJECT_UNLOCK (device);
    return TRUE;
  }

  if (!_physical_device_info (device, error))
    goto error;

  gpu = gst_vulkan_device_get_physical_device (device);

  /* Look for validation layers */
  err = vkEnumerateDeviceLayerProperties (gpu, &device_layer_count, NULL);
  if (gst_vulkan_error_to_g_error (err, error,
          "vkEnumerateDeviceLayerProperties") < 0)
    goto error;

  device_layers = g_new0 (VkLayerProperties, device_layer_count);
  err =
      vkEnumerateDeviceLayerProperties (gpu, &device_layer_count,
      device_layers);
  if (gst_vulkan_error_to_g_error (err, error,
          "vkEnumerateDeviceLayerProperties") < 0) {
    g_free (device_layers);
    goto error;
  }

  _check_for_all_layers (G_N_ELEMENTS (device_validation_layers),
      device_validation_layers, device_layer_count, device_layers,
      &enabled_layer_count, &enabled_layers);
  g_free (device_layers);
  device_layers = NULL;

  err =
      vkEnumerateDeviceExtensionProperties (gpu, NULL,
      &device_extension_count, NULL);
  if (gst_vulkan_error_to_g_error (err, error,
          "vkEnumerateDeviceExtensionProperties") < 0) {
    g_strfreev (enabled_layers);
    goto error;
  }
  GST_DEBUG_OBJECT (device, "Found %u extensions", device_extension_count);

  have_swapchain_ext = 0;
  enabled_extension_count = 0;
  memset (extension_names, 0, sizeof (extension_names));
  device_extensions = g_new0 (VkExtensionProperties, device_extension_count);
  err = vkEnumerateDeviceExtensionProperties (gpu, NULL,
      &device_extension_count, device_extensions);
  if (gst_vulkan_error_to_g_error (err, error,
          "vkEnumerateDeviceExtensionProperties") < 0) {
    g_strfreev (enabled_layers);
    g_free (device_extensions);
    goto error;
  }

  for (uint32_t i = 0; i < device_extension_count; i++) {
    GST_TRACE_OBJECT (device, "checking device extension %s",
        device_extensions[i].extensionName);
    if (!strcmp (VK_KHR_SWAPCHAIN_EXTENSION_NAME,
            device_extensions[i].extensionName)) {
      have_swapchain_ext = TRUE;
      extension_names[enabled_extension_count++] =
          (gchar *) VK_KHR_SWAPCHAIN_EXTENSION_NAME;
    }
    g_assert (enabled_extension_count < 64);
  }
  if (!have_swapchain_ext) {
    g_set_error_literal (error, GST_VULKAN_ERROR,
        VK_ERROR_EXTENSION_NOT_PRESENT,
        "Failed to find required extension, \"" VK_KHR_SWAPCHAIN_EXTENSION_NAME
        "\"");
    g_strfreev (enabled_layers);
    goto error;
  }
  g_free (device_extensions);

  vkGetPhysicalDeviceProperties (gpu, &device->gpu_props);
  vkGetPhysicalDeviceMemoryProperties (gpu, &device->memory_properties);
  vkGetPhysicalDeviceFeatures (gpu, &device->gpu_features);

  vkGetPhysicalDeviceQueueFamilyProperties (gpu, &device->n_queue_families,
      NULL);
  g_assert (device->n_queue_families >= 1);

  device->queue_family_props =
      g_new0 (VkQueueFamilyProperties, device->n_queue_families);
  vkGetPhysicalDeviceQueueFamilyProperties (gpu, &device->n_queue_families,
      device->queue_family_props);

  /* FIXME: allow overriding/selecting */
  for (i = 0; i < device->n_queue_families; i++) {
    if (device->queue_family_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
      break;
  }
  if (i >= device->n_queue_families) {
    g_set_error (error, GST_VULKAN_ERROR, VK_ERROR_INITIALIZATION_FAILED,
        "Failed to find a compatible queue family");
    g_strfreev (enabled_layers);
    goto error;
  }
  device->queue_family_id = i;
  device->n_queues = 1;

  {
    VkDeviceQueueCreateInfo queue_info = { 0, };
    VkDeviceCreateInfo device_info = { 0, };
    gfloat queue_priority = 0.5;

    queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    queue_info.pNext = NULL;
    queue_info.queueFamilyIndex = device->queue_family_id;
    queue_info.queueCount = device->n_queues;
    queue_info.pQueuePriorities = &queue_priority;

    device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    device_info.pNext = NULL;
    device_info.queueCreateInfoCount = 1;
    device_info.pQueueCreateInfos = &queue_info;
    device_info.enabledLayerCount = enabled_layer_count;
    device_info.ppEnabledLayerNames = (const char *const *) enabled_layers;
    device_info.enabledExtensionCount = enabled_extension_count;
    device_info.ppEnabledExtensionNames = (const char *const *) extension_names;
    device_info.pEnabledFeatures = NULL;

    err = vkCreateDevice (gpu, &device_info, NULL, &device->device);
    if (gst_vulkan_error_to_g_error (err, error, "vkCreateDevice") < 0) {
      g_strfreev (enabled_layers);
      goto error;
    }
  }
  g_strfreev (enabled_layers);

  {
    VkCommandPoolCreateInfo cmd_pool_info = { 0, };

    cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
    cmd_pool_info.pNext = NULL;
    cmd_pool_info.queueFamilyIndex = device->queue_family_id;
    cmd_pool_info.flags = 0;

    err =
        vkCreateCommandPool (device->device, &cmd_pool_info, NULL,
        &device->cmd_pool);
    if (gst_vulkan_error_to_g_error (err, error, "vkCreateCommandPool") < 0)
      goto error;
  }

  GST_OBJECT_UNLOCK (device);
  return TRUE;

error:
  {
    GST_OBJECT_UNLOCK (device);
    return FALSE;
  }
}
Exemplo n.º 14
0
//==============================================================================
// Vulkan初期化
//==============================================================================
bool initVulkan(HINSTANCE hinst, HWND wnd)
{
	VkResult result;

	//==================================================
	// Vulkanのインスタンス作成
	//==================================================
	VkApplicationInfo applicationInfo = {};
	applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
	applicationInfo.pApplicationName = APPLICATION_NAME;
	applicationInfo.pEngineName = APPLICATION_NAME;
	applicationInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);

	std::vector<LPCSTR> enabledExtensionsByInstance = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME };

	VkInstanceCreateInfo instanceCreateInfo = {};
	instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
	instanceCreateInfo.pNext = nullptr;
	instanceCreateInfo.pApplicationInfo = &applicationInfo;

	if(enabledExtensionsByInstance.empty() == false)
	{
		instanceCreateInfo.enabledExtensionCount = enabledExtensionsByInstance.size();
		instanceCreateInfo.ppEnabledExtensionNames = enabledExtensionsByInstance.data();
	}

	result = vkCreateInstance(&instanceCreateInfo, nullptr, &g_VulkanInstance);
	checkVulkanError(result, TEXT("Vulkanインスタンス作成失敗"));

	//==================================================
	// 物理デバイス(GPUデバイス)
	//==================================================
	// 物理デバイス数を獲得
	uint32_t gpuCount = 0;
	vkEnumeratePhysicalDevices(g_VulkanInstance, &gpuCount, nullptr);
	assert(gpuCount > 0 && TEXT("物理デバイス数の獲得失敗"));

	// 物理デバイス数を列挙
	std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
	result = vkEnumeratePhysicalDevices(g_VulkanInstance, &gpuCount, physicalDevices.data());
	checkVulkanError(result, TEXT("物理デバイスの列挙に失敗しました"));

	// すべてのGPU情報を格納
	g_GPUs.resize(gpuCount);
	for(uint32_t i = 0; i < gpuCount; ++i)
	{
		g_GPUs[i].device = physicalDevices[i];

		// 物理デバイスのプロパティ獲得
		vkGetPhysicalDeviceProperties(g_GPUs[i].device, &g_GPUs[i].deviceProperties);

		// 物理デバイスのメモリプロパティ獲得
		vkGetPhysicalDeviceMemoryProperties(g_GPUs[i].device, &g_GPUs[i].deviceMemoryProperties);
	}

	// ※このサンプルでは最初に列挙されたGPUデバイスを使用する
	g_currentGPU = g_GPUs[0];

	// グラフィックス操作をサポートするキューを検索
	uint32_t queueCount;
	vkGetPhysicalDeviceQueueFamilyProperties(g_currentGPU.device, &queueCount, nullptr);
	assert(queueCount >= 1 && TEXT("物理デバイスキューの検索失敗"));

	std::vector<VkQueueFamilyProperties> queueProps;
	queueProps.resize(queueCount);
	vkGetPhysicalDeviceQueueFamilyProperties(g_currentGPU.device, &queueCount, queueProps.data());

	uint32_t graphicsQueueIndex = 0;
	for(graphicsQueueIndex = 0; graphicsQueueIndex < queueCount; ++graphicsQueueIndex)
	{
		if(queueProps[graphicsQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT)
		{
			break;
		}
	}
	assert(graphicsQueueIndex < queueCount && TEXT("グラフィックスをサポートするキューを見つけられませんでした"));

	//==================================================
	// Vulkanデバイス作成
	//==================================================
	float queuePrioritie = 0.0f;
	VkDeviceQueueCreateInfo queueCreateInfo = {};
	queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
	queueCreateInfo.queueFamilyIndex = graphicsQueueIndex;
	queueCreateInfo.queueCount = 1;
	queueCreateInfo.pQueuePriorities = &queuePrioritie;

	std::vector<LPCSTR> enabledExtensionsByDevice = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };

	VkDeviceCreateInfo deviceCreateInfo = {};
	deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
	deviceCreateInfo.pNext = nullptr;
	deviceCreateInfo.queueCreateInfoCount = 1;
	deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
	deviceCreateInfo.pEnabledFeatures = nullptr;

	if(enabledExtensionsByDevice.empty() == false)
	{
		deviceCreateInfo.enabledExtensionCount = enabledExtensionsByDevice.size();
		deviceCreateInfo.ppEnabledExtensionNames = enabledExtensionsByDevice.data();
	}

	result = vkCreateDevice(g_currentGPU.device, &deviceCreateInfo, nullptr, &g_VulkanDevice);
	checkVulkanError(result, TEXT("Vulkanデバイス作成失敗"));

	// グラフィックスキュー獲得
	vkGetDeviceQueue(g_VulkanDevice, graphicsQueueIndex, 0, &g_VulkanQueue);

	//==================================================
	// フェンスオブジェクト作成
	//==================================================
	VkFenceCreateInfo fenceCreateInfo = {};
	fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
	fenceCreateInfo.pNext = nullptr;
	fenceCreateInfo.flags = 0;
	result = vkCreateFence(g_VulkanDevice, &fenceCreateInfo, nullptr, &g_VulkanFence);
	checkVulkanError(result, TEXT("フェンスオブジェクト作成失敗"));

	//==================================================
	// 同期(セマフォ)オブジェクト作成
	//==================================================
	VkSemaphoreCreateInfo semaphoreCreateInfo = {};
	semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
	semaphoreCreateInfo.pNext = nullptr;
	semaphoreCreateInfo.flags = 0;

	// コマンドバッファ実行用セマフォ作成
	result = vkCreateSemaphore(g_VulkanDevice, &semaphoreCreateInfo, nullptr, &g_VulkanSemahoreRenderComplete);
	checkVulkanError(result, TEXT("コマンドバッファ実行用セマフォ作成失敗"));

	//==================================================
	// コマンドプール作製
	//==================================================
	VkCommandPoolCreateInfo cmdPoolInfo = {};
	cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
	cmdPoolInfo.queueFamilyIndex = 0;
	cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
	result = vkCreateCommandPool(g_VulkanDevice, &cmdPoolInfo, nullptr, &g_VulkanCommandPool);
	checkVulkanError(result, TEXT("コマンドプール作成失敗"));

	//==================================================
	// コマンドバッファ作成
	//==================================================
	// メモリを確保.
	g_commandBuffers.resize(SWAP_CHAIN_COUNT);

	VkCommandBufferAllocateInfo commandBufferAllocateInfo = {};
	commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
	commandBufferAllocateInfo.pNext = nullptr;
	commandBufferAllocateInfo.commandPool = g_VulkanCommandPool;
	commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
	commandBufferAllocateInfo.commandBufferCount = SWAP_CHAIN_COUNT;

	result = vkAllocateCommandBuffers(g_VulkanDevice, &commandBufferAllocateInfo, g_commandBuffers.data());
	checkVulkanError(result, TEXT("コマンドバッファ作成失敗"));

	//==================================================
	// OS(今回はWin32)用のサーフェスを作成する
	//==================================================
	VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
	surfaceCreateInfo.hinstance = hinst;
	surfaceCreateInfo.hwnd = wnd;
	result = vkCreateWin32SurfaceKHR(g_VulkanInstance, &surfaceCreateInfo, nullptr, &g_VulkanSurface);
	checkVulkanError(result, TEXT("サーフェス作成失敗"));

	//==================================================
	// スワップチェーンを作成する
	//==================================================
	VkFormat        imageFormat = VK_FORMAT_R8G8B8A8_UNORM;
	VkColorSpaceKHR imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;

	uint32_t surfaceFormatCount = 0;
	result = vkGetPhysicalDeviceSurfaceFormatsKHR(g_currentGPU.device, g_VulkanSurface, &surfaceFormatCount, nullptr);
	checkVulkanError(result, TEXT("サポートしているカラーフォーマット数の獲得失敗"));

	std::vector<VkSurfaceFormatKHR> surfaceFormats;
	surfaceFormats.resize(surfaceFormatCount);
	result = vkGetPhysicalDeviceSurfaceFormatsKHR(g_currentGPU.device, g_VulkanSurface, &surfaceFormatCount, surfaceFormats.data());
	checkVulkanError(result, TEXT("サポートしているカラーフォーマットの獲得失敗"));

	// 一致するカラーフォーマットを検索する
	bool isFind = false;
	for(const auto& surfaceFormat : surfaceFormats)
	{
		if(imageFormat == surfaceFormat.format &&
			imageColorSpace == surfaceFormat.colorSpace)
		{
			isFind = true;
			break;
		}
	}

	if(isFind == false)
	{
		imageFormat = surfaceFormats[0].format;
		imageColorSpace = surfaceFormats[0].colorSpace;
	}

	// サーフェスの機能を獲得する
	VkSurfaceCapabilitiesKHR surfaceCapabilities;
	VkSurfaceTransformFlagBitsKHR surfaceTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
	result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
		g_currentGPU.device,
		g_VulkanSurface,
		&surfaceCapabilities);
	checkVulkanError(result, TEXT("サーフェスの機能の獲得失敗"));

	if((surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) == 0)
	{
		surfaceTransform = surfaceCapabilities.currentTransform;
	}

	// プレゼント機能を獲得する
	VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
	uint32_t presentModeCount;
	result = vkGetPhysicalDeviceSurfacePresentModesKHR(
		g_currentGPU.device,
		g_VulkanSurface,
		&presentModeCount,
		nullptr);
	checkVulkanError(result, TEXT("プレゼント機能数の獲得失敗"));

	std::vector<VkPresentModeKHR> presentModes;
	presentModes.resize(presentModeCount);
	result = vkGetPhysicalDeviceSurfacePresentModesKHR(
		g_currentGPU.device,
		g_VulkanSurface,
		&presentModeCount,
		presentModes.data());
	checkVulkanError(result, TEXT("プレゼント機能の獲得失敗"));

	for(const auto& presentModeInfo : presentModes)
	{
		if(presentModeInfo == VK_PRESENT_MODE_MAILBOX_KHR)
		{
			presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
			break;
		}
		if(presentModeInfo == VK_PRESENT_MODE_IMMEDIATE_KHR)
		{
			presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
		}
	}

	presentModes.clear();

	uint32_t desiredSwapChainImageCount = surfaceCapabilities.minImageCount + 1;
	if(surfaceCapabilities.maxImageCount > 0 && desiredSwapChainImageCount > surfaceCapabilities.maxImageCount)
	{
		desiredSwapChainImageCount = surfaceCapabilities.maxImageCount;
	}

	// スワップチェーン作成
	VkSwapchainCreateInfoKHR swapchainCreateInfo = {};
	swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
	swapchainCreateInfo.pNext = nullptr;
	swapchainCreateInfo.flags = 0;
	swapchainCreateInfo.surface = g_VulkanSurface;
	swapchainCreateInfo.minImageCount = desiredSwapChainImageCount;
	swapchainCreateInfo.imageFormat = imageFormat;
	swapchainCreateInfo.imageColorSpace = imageColorSpace;
	swapchainCreateInfo.imageExtent = { SCREEN_WIDTH, SCREEN_HEIGHT };
	swapchainCreateInfo.imageArrayLayers = 1;
	swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
	swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
	swapchainCreateInfo.queueFamilyIndexCount = 0;
	swapchainCreateInfo.pQueueFamilyIndices = nullptr;
	swapchainCreateInfo.preTransform = surfaceTransform;
	swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
	swapchainCreateInfo.presentMode = presentMode;
	swapchainCreateInfo.clipped = VK_TRUE;
	swapchainCreateInfo.oldSwapchain = VK_NULL_HANDLE;

	result = vkCreateSwapchainKHR(g_VulkanDevice, &swapchainCreateInfo, nullptr, &g_VulkanSwapChain);
	checkVulkanError(result, TEXT("サーフェス作成失敗"));

	//==================================================
	// イメージの作成
	//==================================================
	uint32_t swapChainCount = 0;
	result = vkGetSwapchainImagesKHR(g_VulkanDevice, g_VulkanSwapChain, &swapChainCount, nullptr);
	checkVulkanError(result, TEXT("スワップチェーンイメージ数の獲得失敗"));

	g_backBuffersTextures.resize(swapChainCount);

	std::vector<VkImage> images;
	images.resize(swapChainCount);
	result = vkGetSwapchainImagesKHR(g_VulkanDevice, g_VulkanSwapChain, &swapChainCount, images.data());
	checkVulkanError(result, TEXT("スワップチェーンイメージの獲得失敗"));

	for(uint32_t i = 0; i < swapChainCount; ++i)
	{
		g_backBuffersTextures[i].image = images[i];
	}

	images.clear();

	//==================================================
	// イメージビューの生成
	//==================================================
	for(auto& backBuffer : g_backBuffersTextures)
	{
		VkImageViewCreateInfo imageViewCreateInfo = {};
		imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
		imageViewCreateInfo.pNext = nullptr;
		imageViewCreateInfo.flags = 0;
		imageViewCreateInfo.image = backBuffer.image;
		imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
		imageViewCreateInfo.format = imageFormat;
		imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
		imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G;
		imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B;
		imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A;
		imageViewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };

		result = vkCreateImageView(g_VulkanDevice, &imageViewCreateInfo, nullptr, &backBuffer.view);
		checkVulkanError(result, TEXT("イメージビューの作成失敗"));

		setImageLayout(
			g_VulkanDevice,
			g_commandBuffers[g_currentBufferIndex],
			backBuffer.image,
			VK_IMAGE_ASPECT_COLOR_BIT,
			VK_IMAGE_LAYOUT_UNDEFINED,
			VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
	}

	//==================================================
	// 深度ステンシルバッファの生成
	//==================================================
	VkFormat depthFormat = VK_FORMAT_D24_UNORM_S8_UINT;

	VkImageTiling imageTiling;
	VkFormatProperties formatProperties;
	vkGetPhysicalDeviceFormatProperties(g_currentGPU.device, depthFormat, &formatProperties);

	if(formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
	{
		imageTiling = VK_IMAGE_TILING_LINEAR;
	}
	else if(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
	{
		imageTiling = VK_IMAGE_TILING_OPTIMAL;
	}
	else
	{
		checkVulkanError(VK_RESULT_MAX_ENUM, TEXT("サポートされていないフォーマットです"));
		return false;
	}

	VkImageCreateInfo imageCreateInfo = {};
	imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
	imageCreateInfo.pNext = nullptr;
	imageCreateInfo.flags = 0;
	imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
	imageCreateInfo.format = depthFormat;
	imageCreateInfo.extent.width = SCREEN_WIDTH;
	imageCreateInfo.extent.height = SCREEN_HEIGHT;
	imageCreateInfo.extent.depth = 1;
	imageCreateInfo.mipLevels = 1;
	imageCreateInfo.arrayLayers = 1;
	imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
	imageCreateInfo.tiling = imageTiling;
	imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
	imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
	imageCreateInfo.queueFamilyIndexCount = 0;
	imageCreateInfo.pQueueFamilyIndices = nullptr;
	imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

	result = vkCreateImage(g_VulkanDevice, &imageCreateInfo, nullptr, &g_depthBufferTexture.image);
	checkVulkanError(result, TEXT("深度テクスチャ用イメージビュー作成失敗"));

	// メモリ要件を獲得
	VkMemoryRequirements memoryRequirements;
	vkGetImageMemoryRequirements(g_VulkanDevice, g_depthBufferTexture.image, &memoryRequirements);

	VkFlags requirementsMask = 0;
	uint32_t typeBits = memoryRequirements.memoryTypeBits;
	uint32_t typeIndex = 0;

	for(const auto& memoryType : g_currentGPU.deviceMemoryProperties.memoryTypes)
	{
		if((typeBits & 0x1) == 1)
		{
			if((memoryType.propertyFlags & requirementsMask) == requirementsMask)
			{
				break;
			}
		}
		typeBits >>= 1;
		++typeIndex;
	}

	// メモリ確保
	VkMemoryAllocateInfo allocInfo = {};
	allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
	allocInfo.pNext = nullptr;
	allocInfo.allocationSize = memoryRequirements.size;
	allocInfo.memoryTypeIndex = typeIndex;

	result = vkAllocateMemory(g_VulkanDevice, &allocInfo, nullptr, &g_depthBufferTexture.memory);
	checkVulkanError(result, TEXT("深度テクスチャ用メモリ確保失敗"));

	result = vkBindImageMemory(g_VulkanDevice, g_depthBufferTexture.image, g_depthBufferTexture.memory, 0);
	checkVulkanError(result, TEXT("深度テクスチャメモリにバインド失敗"));

	VkImageViewCreateInfo imageViewCreateInfo = {};
	imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
	imageViewCreateInfo.pNext = nullptr;
	imageViewCreateInfo.image = g_depthBufferTexture.image;
	imageViewCreateInfo.format = depthFormat;
	imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
	imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G;
	imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B;
	imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A;
	imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
	imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
	imageViewCreateInfo.subresourceRange.levelCount = 1;
	imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
	imageViewCreateInfo.subresourceRange.layerCount = 1;
	imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
	imageViewCreateInfo.flags = 0;

	result = vkCreateImageView(g_VulkanDevice, &imageViewCreateInfo, nullptr, &g_depthBufferTexture.view);
	checkVulkanError(result, TEXT("深度テクスチャイメージビュー作成失敗"));

	setImageLayout(
		g_VulkanDevice,
		g_commandBuffers[g_currentBufferIndex],
		g_depthBufferTexture.image,
		VK_IMAGE_ASPECT_DEPTH_BIT,
		VK_IMAGE_LAYOUT_UNDEFINED,
		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);

	//==================================================
	// フレームバッファの生成
	//==================================================
	VkImageView attachments[2];	// 0=カラーバッファ、1=深度バッファ

	VkFramebufferCreateInfo frameBufferCreateInfo = {};
	frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
	frameBufferCreateInfo.pNext = nullptr;
	frameBufferCreateInfo.flags = 0;
	frameBufferCreateInfo.renderPass = VK_NULL_HANDLE;
	frameBufferCreateInfo.attachmentCount = 2;
	frameBufferCreateInfo.pAttachments = attachments;
	frameBufferCreateInfo.width = SCREEN_WIDTH;
	frameBufferCreateInfo.height = SCREEN_HEIGHT;
	frameBufferCreateInfo.layers = 1;

	g_frameBuffers.resize(SWAP_CHAIN_COUNT);
	for(uint32_t i = 0; i < SWAP_CHAIN_COUNT; ++i)
	{
		attachments[0] = g_backBuffersTextures[i].view;
		attachments[1] = g_depthBufferTexture.view;
		auto result = vkCreateFramebuffer(g_VulkanDevice, &frameBufferCreateInfo, nullptr, &g_frameBuffers[i]);
		checkVulkanError(result, TEXT("フレームバッファ作成失敗"));
	}

	return true;
}
Exemplo n.º 15
0
void VulkanBase::initVulkan(bool enableValidation) {
	VkResult err = createInstance(enableValidation);
	if (err) vkTools::exitFatal("Could not create Vulkan instance : \n" + vkTools::errorString(err), "Fatal error");

	uint32_t gpuCount = 0;
	err = vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr);
	assert(!err);
	assert(gpuCount > 0);

	std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
	err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
	if (err) vkTools::exitFatal("Could not enumerate phyiscal devices : \n" + vkTools::errorString(err), "Fatal error");

	physicalDevice = physicalDevices[0];

	uint32_t graphicsQueueIndex = 0;
	uint32_t queueCount;
	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL);
	assert(queueCount >= 1);

	std::vector<VkQueueFamilyProperties> queueProps;
	queueProps.resize(queueCount);
	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data());

	for (graphicsQueueIndex = 0; graphicsQueueIndex < queueCount; graphicsQueueIndex++)
		if (queueProps[graphicsQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT)
			break;
	assert(graphicsQueueIndex < queueCount);

	std::array<float, 1> queuePriorities = { 0.0f };
	VkDeviceQueueCreateInfo queueCreateInfo = {};
	queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
	queueCreateInfo.queueFamilyIndex = graphicsQueueIndex;
	queueCreateInfo.queueCount = 1;
	queueCreateInfo.pQueuePriorities = queuePriorities.data();

	err = createDevice(queueCreateInfo, enableValidation);
	assert(!err);

	vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);

	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);

	vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);

	VkBool32 validDepthFormat = vkTools::getSupportedDepthFormat(physicalDevice, &depthFormat);
	assert(validDepthFormat);

	swapChain.connect(instance, physicalDevice, device);

	VkSemaphoreCreateInfo semaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo();

	err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.presentComplete);
	assert(!err);

	err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.renderComplete);
	assert(!err);

	submitInfo = vkTools::initializers::submitInfo();
	submitInfo.pWaitDstStageMask = &submitPipelineStages;
	submitInfo.waitSemaphoreCount = 1;
	submitInfo.pWaitSemaphores = &semaphores.presentComplete;
	submitInfo.signalSemaphoreCount = 1;
	submitInfo.pSignalSemaphores = &semaphores.renderComplete;
}
Exemplo n.º 16
0
bool VulkanDevice::Init(VulkanInstance * vulkanInstance, HWND hwnd)
{
	VkResult result;

	// GPU
	uint32_t numGPUs = 0;
	vkEnumeratePhysicalDevices(vulkanInstance->GetInstance(), &numGPUs, VK_NULL_HANDLE);
	if (numGPUs == 0)
	{
		gLogManager->AddMessage("ERROR: No GPUs found!");
		return false;
	}

	std::vector<VkPhysicalDevice> pGPUs(numGPUs);
	vkEnumeratePhysicalDevices(vulkanInstance->GetInstance(), &numGPUs, pGPUs.data());
	gpu = pGPUs[0];

	vkGetPhysicalDeviceProperties(gpu, &gpuProperties);
	vkGetPhysicalDeviceMemoryProperties(gpu, &memoryProperties);
	gLogManager->AddMessage("Rendering with: " + std::string(gpuProperties.deviceName));

	// Queue family
	uint32_t numQueueFamily = 0;
	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &numQueueFamily, VK_NULL_HANDLE);
	if (numQueueFamily == 0)
	{
		gLogManager->AddMessage("ERROR: No Queue Families were found!");
		return false;
	}

	queueFamiliyProperties.resize(numQueueFamily);
	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &numQueueFamily, queueFamiliyProperties.data());

	// Surface
	VkWin32SurfaceCreateInfoKHR win32SurfaceCI{};
	win32SurfaceCI.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
	win32SurfaceCI.hinstance = GetModuleHandle(NULL);
	win32SurfaceCI.hwnd = hwnd;

	result = vkCreateWin32SurfaceKHR(vulkanInstance->GetInstance(), &win32SurfaceCI, VK_NULL_HANDLE, &surface);
	if (result != VK_SUCCESS)
	{
		gLogManager->AddMessage("ERROR: Couldn't create Win32 Surface!");
		return false;
	}

	VkBool32 * supportsPresent = new VkBool32[queueFamiliyProperties.size()];
	for (uint32_t i = 0; i < queueFamiliyProperties.size(); i++)
		vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supportsPresent[i]);

	graphicsQueueFamilyIndex = UINT32_MAX;
	for (uint32_t i = 0; i < queueFamiliyProperties.size(); i++)
	{
		if ((queueFamiliyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
		{
			if (supportsPresent[i] == VK_TRUE)
			{
				graphicsQueueFamilyIndex = i;
				break;
			}
		}
	}

	delete[] supportsPresent;

	if (graphicsQueueFamilyIndex == UINT32_MAX)
	{
		gLogManager->AddMessage("ERROR: Couldn't find a graphics queue family index!");
		return false;
	}

	uint32_t numFormats;
	result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &numFormats, VK_NULL_HANDLE);
	if (result != VK_SUCCESS)
	{
		gLogManager->AddMessage("ERROR: Couldn't get surface formats!");
		return false;
	}

	VkSurfaceFormatKHR * pSurfaceFormats = new VkSurfaceFormatKHR[numFormats];
	result = vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &numFormats, pSurfaceFormats);

	if (numFormats == 1 && pSurfaceFormats[0].format == VK_FORMAT_UNDEFINED)
		format = VK_FORMAT_B8G8R8A8_UNORM;
	else
		format = pSurfaceFormats[0].format;

	// Device queue

	float pQueuePriorities[] = { 1.0f };
	VkDeviceQueueCreateInfo deviceQueueCI{};
	deviceQueueCI.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
	deviceQueueCI.queueCount = 1;
	deviceQueueCI.queueFamilyIndex = graphicsQueueFamilyIndex;
	deviceQueueCI.pQueuePriorities = pQueuePriorities;

	VkPhysicalDeviceFeatures deviceFeatures{};
	deviceFeatures.shaderClipDistance = VK_TRUE;
	deviceFeatures.shaderCullDistance = VK_TRUE;
	deviceFeatures.geometryShader = VK_TRUE;
	deviceFeatures.shaderTessellationAndGeometryPointSize = VK_TRUE;
	deviceFeatures.fillModeNonSolid = VK_TRUE;

	// Device
	VkDeviceCreateInfo deviceCI{};
	deviceCI.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
	deviceCI.queueCreateInfoCount = 1;
	deviceCI.pQueueCreateInfos = &deviceQueueCI;
	deviceCI.enabledExtensionCount = (uint32_t)deviceExtensions.size();
	deviceCI.ppEnabledExtensionNames = deviceExtensions.data();
	deviceCI.pEnabledFeatures = &deviceFeatures;

	result = vkCreateDevice(gpu, &deviceCI, VK_NULL_HANDLE, &device);
	if (result != VK_SUCCESS)
	{
		gLogManager->AddMessage("ERROR: vkCreateDevice() failed!");
		return false;
	}

	vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &deviceQueue);
	return true;
}
Exemplo n.º 17
0
void vulkan_choose_physical_device(ReaperRoot& root, VulkanBackend& backend, PhysicalDeviceInfo& physicalDeviceInfo)
{
    uint32_t deviceCount = 0;

    Assert(vkEnumeratePhysicalDevices(backend.instance, &deviceCount, nullptr) == VK_SUCCESS);
    Assert(deviceCount > 0);

    log_debug(root, "vulkan: enumerating {} physical devices", deviceCount);

    std::vector<VkPhysicalDevice> availableDevices(deviceCount);
    Assert(vkEnumeratePhysicalDevices(backend.instance, &deviceCount, &availableDevices[0]) == VK_SUCCESS,
           "error occurred during physical devices enumeration");

    uint32_t selected_queue_family_index = UINT32_MAX;
    uint32_t selected_present_queue_family_index = UINT32_MAX;

    // Duplicated two times TODO merge
    std::vector<const char*> extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};

    VkPhysicalDevice chosenPhysicalDevice = VK_NULL_HANDLE;
    for (auto& device : availableDevices)
    {
        if (vulkan_check_physical_device(root.renderer->window,
                                         device,
                                         backend.presentInfo.surface,
                                         extensions,
                                         selected_queue_family_index,
                                         selected_present_queue_family_index))
        {
            chosenPhysicalDevice = device;
            break;
        }
    }

    Assert(chosenPhysicalDevice != VK_NULL_HANDLE, "could not select physical device based on the chosen properties");

    physicalDeviceInfo.graphicsQueueIndex = selected_queue_family_index;
    physicalDeviceInfo.presentQueueIndex = selected_present_queue_family_index;

    vkGetPhysicalDeviceMemoryProperties(chosenPhysicalDevice, &physicalDeviceInfo.memory);

    // re-fetch device infos TODO avoid
    VkPhysicalDeviceProperties physicalDeviceProperties;
    vkGetPhysicalDeviceProperties(chosenPhysicalDevice, &physicalDeviceProperties);

    log_info(root, "vulkan: selecting device '{}'", physicalDeviceProperties.deviceName);
    log_debug(root, "- type = {}", vulkan_physical_device_type_name(physicalDeviceProperties.deviceType));

    uint32_t apiVersion = physicalDeviceProperties.apiVersion;
    uint32_t driverVersion = physicalDeviceProperties.driverVersion;
    log_debug(root,
              "- api version = {}.{}.{}",
              VK_VERSION_MAJOR(apiVersion),
              VK_VERSION_MINOR(apiVersion),
              VK_VERSION_PATCH(apiVersion));
    log_debug(root,
              "- driver version = {}.{}.{}",
              VK_VERSION_MAJOR(driverVersion),
              VK_VERSION_MINOR(driverVersion),
              VK_VERSION_PATCH(driverVersion));

    log_debug(root,
              "- memory type count = {}, memory heap count = {}",
              physicalDeviceInfo.memory.memoryTypeCount,
              physicalDeviceInfo.memory.memoryHeapCount);

    for (u32 i = 0; i < physicalDeviceInfo.memory.memoryHeapCount; ++i)
    {
        VkMemoryHeap& heap = physicalDeviceInfo.memory.memoryHeaps[i];
        log_debug(root, "- heap {}: available size = {}, flags = {}", i, heap.size, heap.flags);
    }

    backend.physicalDevice = chosenPhysicalDevice;
}
Exemplo n.º 18
0
/**
 * Good ol' main function.
 */
int main(int argc, char* argv[])
{
	static int windowWidth = 800;
	static int windowHeight = 600;
	static const char * applicationName = "SdlVulkanDemo_03_double_buffering";
	static const char * engineName = applicationName;

	bool boolResult;
	VkResult result;

	/*
	 * SDL2 Initialization
	 */
	SDL_Window *mySdlWindow;
	SDL_SysWMinfo mySdlSysWmInfo;

	boolResult = vkdemos::utils::sdl2Initialization(applicationName, windowWidth, windowHeight, mySdlWindow, mySdlSysWmInfo);
	assert(boolResult);

	/*
	 * Vulkan initialization.
	 */
	std::vector<const char *> layersNamesToEnable;
	layersNamesToEnable.push_back("VK_LAYER_LUNARG_standard_validation");

	std::vector<const char *> extensionsNamesToEnable;
	extensionsNamesToEnable.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
	extensionsNamesToEnable.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
	extensionsNamesToEnable.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); // TODO: add support for other windowing systems

	VkInstance myInstance;
	boolResult = vkdemos::createVkInstance(layersNamesToEnable, extensionsNamesToEnable, applicationName, engineName, myInstance);
	assert(boolResult);

	VkDebugReportCallbackEXT myDebugReportCallback;
	vkdemos::createDebugReportCallback(myInstance,
		VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT,
		vkdemos::debugCallback,
		myDebugReportCallback
	);

	VkPhysicalDevice myPhysicalDevice;
	boolResult = vkdemos::chooseVkPhysicalDevice(myInstance, 0, myPhysicalDevice);
	assert(boolResult);

	VkSurfaceKHR mySurface;
	boolResult = vkdemos::createVkSurface(myInstance, mySdlSysWmInfo, mySurface);
	assert(boolResult);

	VkDevice myDevice;
	VkQueue myQueue;
	uint32_t myQueueFamilyIndex;
	boolResult = vkdemos::createVkDeviceAndVkQueue(myPhysicalDevice, mySurface, layersNamesToEnable, myDevice, myQueue, myQueueFamilyIndex);
	assert(boolResult);

	VkSwapchainKHR mySwapchain;
	VkFormat mySurfaceFormat;
	boolResult = vkdemos::createVkSwapchain(myPhysicalDevice, myDevice, mySurface, windowWidth, windowHeight, FRAME_LAG, VK_NULL_HANDLE, mySwapchain, mySurfaceFormat);
	assert(boolResult);

	std::vector<VkImage> mySwapchainImagesVector;
	std::vector<VkImageView> mySwapchainImageViewsVector;
	boolResult = vkdemos::getSwapchainImagesAndViews(myDevice, mySwapchain, mySurfaceFormat, mySwapchainImagesVector, mySwapchainImageViewsVector);
	assert(boolResult);

	VkCommandPool myCommandPool;
	boolResult = vkdemos::createCommandPool(myDevice, myQueueFamilyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, myCommandPool);
	assert(boolResult);

	VkCommandBuffer myCmdBufferInitialization;
	boolResult = vkdemos::allocateCommandBuffer(myDevice, myCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, myCmdBufferInitialization);
	assert(boolResult);


	/*
	 * Initializations from Demo 02 (Triangle).
	 */
	VkPhysicalDeviceMemoryProperties myMemoryProperties;
	vkGetPhysicalDeviceMemoryProperties(myPhysicalDevice, &myMemoryProperties);

	// Create the Depth Buffer's Image and View.
	const VkFormat myDepthBufferFormat = VK_FORMAT_D16_UNORM;

	VkImage myDepthImage;
	VkImageView myDepthImageView;
	VkDeviceMemory myDepthMemory;
	boolResult = vkdemos::createAndAllocateImage(myDevice,
	                                    myMemoryProperties,
	                                    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
	                                    0,
	                                    myDepthBufferFormat,
	                                    windowWidth,
	                                    windowHeight,
	                                    myDepthImage,
	                                    myDepthMemory,
	                                    &myDepthImageView,
	                                    VK_IMAGE_ASPECT_DEPTH_BIT
	                                    );
	assert(boolResult);


	// Create the renderpass.
	VkRenderPass myRenderPass;
	boolResult = demo02CreateRenderPass(myDevice, mySurfaceFormat, myDepthBufferFormat, myRenderPass);
	assert(boolResult);

	// Create the Framebuffers, based on the number of swapchain images.
	std::vector<VkFramebuffer> myFramebuffersVector;
	myFramebuffersVector.reserve(mySwapchainImageViewsVector.size());

	for(const auto view : mySwapchainImageViewsVector) {
		VkFramebuffer fb;
		boolResult = vkdemos::utils::createFramebuffer(myDevice, myRenderPass, {view, myDepthImageView}, windowWidth, windowHeight, fb);
		assert(boolResult);
		myFramebuffersVector.push_back(fb);
	}


	// Create a buffer to use as the vertex buffer.
	const size_t vertexBufferSize = sizeof(TriangleDemoVertex)*NUM_DEMO_VERTICES;
	VkBuffer myVertexBuffer;
	VkDeviceMemory myVertexBufferMemory;
	boolResult = vkdemos::createAndAllocateBuffer(myDevice,
	                                     myMemoryProperties,
	                                     VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
	                                     VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
	                                     vertexBufferSize,
	                                     myVertexBuffer,
	                                     myVertexBufferMemory
	                                     );
	assert(boolResult);

	// Map vertex buffer and insert data
	{
		void *mappedBuffer;
		result = vkMapMemory(myDevice, myVertexBufferMemory, 0, VK_WHOLE_SIZE, 0, &mappedBuffer);
		assert(result == VK_SUCCESS);

		memcpy(mappedBuffer, vertices, vertexBufferSize);

		vkUnmapMemory(myDevice, myVertexBufferMemory);
	}


	// Create the pipeline.
	const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
		.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
		.pNext = nullptr,
		.flags = 0,
		.setLayoutCount = 0,
		.pSetLayouts = nullptr,
		.pushConstantRangeCount = 0,
		.pPushConstantRanges = nullptr,
	};

	VkPipelineLayout myPipelineLayout;
	result = vkCreatePipelineLayout(myDevice, &pipelineLayoutCreateInfo, nullptr, &myPipelineLayout);
	assert(result == VK_SUCCESS);


	// Create Pipeline.
	VkPipeline myGraphicsPipeline;
	boolResult = demo02CreatePipeline(myDevice, myRenderPass, myPipelineLayout, VERTEX_SHADER_FILENAME, FRAGMENT_SHADER_FILENAME, VERTEX_INPUT_BINDING, myGraphicsPipeline);
	assert(boolResult);


	/*
	 * In the PerFrameData struct we group all the objects that are used in a single frame, and that
	 * must remain valid for the duration of that frame.
	 *
	 */
	PerFrameData perFrameDataVector[FRAME_LAG];

	for(int i = 0; i < FRAME_LAG; i++)
	{
		boolResult = vkdemos::allocateCommandBuffer(myDevice, myCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, perFrameDataVector[i].presentCmdBuffer);
		assert(boolResult);

		result = vkdemos::utils::createFence(myDevice, perFrameDataVector[i].presentFence);
		assert(result == VK_SUCCESS);

		result = vkdemos::utils::createSemaphore(myDevice, perFrameDataVector[i].imageAcquiredSemaphore);
		assert(result == VK_SUCCESS);

		result = vkdemos::utils::createSemaphore(myDevice, perFrameDataVector[i].renderingCompletedSemaphore);
		assert(result == VK_SUCCESS);

		perFrameDataVector[i].fenceInitialized = false;
	}


	/*
	 * Generation and submission of the initialization commands' command buffer.
	 */
	// We fill the initialization command buffer with... the initialization commands.
	boolResult = demo02FillInitializationCommandBuffer(myCmdBufferInitialization, myDepthImage);
	assert(boolResult);

	// We now submit the command buffer to the queue we created before, and we wait
	// for its completition.
	VkSubmitInfo submitInfo = {
		.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
		.pNext = nullptr,
		.waitSemaphoreCount = 0,
		.pWaitSemaphores = nullptr,
		.pWaitDstStageMask = nullptr,
		.commandBufferCount = 1,
		.pCommandBuffers = &myCmdBufferInitialization,
		.signalSemaphoreCount = 0,
		.pSignalSemaphores = nullptr
	};

	result = vkQueueSubmit(myQueue, 1, &submitInfo, VK_NULL_HANDLE);
	assert(result == VK_SUCCESS);

	// Wait for the queue to complete its work.
	result = vkQueueWaitIdle(myQueue);
	assert(result == VK_SUCCESS);


	/*
	 * Event loop
	 */
	SDL_Event sdlEvent;
	bool quit = false;

	// Just some variables for frame statistics
	long frameNumber = 0;
	long frameMaxTime = LONG_MIN;
	long frameMinTime = LONG_MAX;
	long frameAvgTimeSum = 0;
	long frameAvgTimeSumSquare = 0;
	constexpr long FRAMES_PER_STAT = 120;	// How many frames to wait before printing frame time statistics.

	// The main event/render loop.
	while(!quit)
	{
		// Process events for this frame
		while(SDL_PollEvent(&sdlEvent))
		{
			if (sdlEvent.type == SDL_QUIT) {
				quit = true;
			}
			if (sdlEvent.type == SDL_KEYDOWN && sdlEvent.key.keysym.sym == SDLK_ESCAPE) {
				quit = true;
			}
		}

		// Rendering code
		if(!quit)
		{
			// Render a single frame
			auto renderStartTime = std::chrono::high_resolution_clock::now();
			quit = !demo03RenderSingleFrame(myDevice, myQueue, mySwapchain, myFramebuffersVector, myRenderPass, myGraphicsPipeline, myVertexBuffer, VERTEX_INPUT_BINDING, perFrameDataVector[frameNumber % FRAME_LAG], windowWidth, windowHeight);
			auto renderStopTime = std::chrono::high_resolution_clock::now();

			// Compute frame time statistics
			auto elapsedTimeUs = std::chrono::duration_cast<std::chrono::microseconds>(renderStopTime - renderStartTime).count();

			frameMaxTime = std::max(frameMaxTime, elapsedTimeUs);
			frameMinTime = std::min(frameMinTime, elapsedTimeUs);
			frameAvgTimeSum += elapsedTimeUs;
			frameAvgTimeSumSquare += elapsedTimeUs*elapsedTimeUs;

			// Print statistics if necessary
			if(frameNumber % FRAMES_PER_STAT == 0)
			{
				auto average = frameAvgTimeSum/FRAMES_PER_STAT;
				auto stddev = std::sqrt(frameAvgTimeSumSquare/FRAMES_PER_STAT - average*average);
				std::cout << "Frame time: average " << std::setw(6) << average
				          << " us, maximum " << std::setw(6) << frameMaxTime
				          << " us, minimum " << std::setw(6) << frameMinTime
				          << " us, stddev " << (long)stddev
				          << " (" << std::fixed << std::setprecision(2) << (stddev/average * 100.0f) << "%)"
				          << std::endl;

				frameMaxTime = LONG_MIN;
				frameMinTime = LONG_MAX;
				frameAvgTimeSum = 0;
				frameAvgTimeSumSquare = 0;
			}

			frameNumber++;
		}
	}


	/*
	 * Deinitialization
	 */
	// We wait for pending operations to complete before starting to destroy stuff.
	result = vkQueueWaitIdle(myQueue);
	assert(result == VK_SUCCESS);

	// Destroy the objects in the perFrameDataVector array.
	for(int i = 0; i < FRAME_LAG; i++)
	{
		vkDestroyFence(myDevice, perFrameDataVector[i].presentFence, nullptr);
		vkDestroySemaphore(myDevice, perFrameDataVector[i].imageAcquiredSemaphore, nullptr);
		vkDestroySemaphore(myDevice, perFrameDataVector[i].renderingCompletedSemaphore, nullptr);
	}

	/*
	 * For more informations on the following commands, refer to Demo 02.
	 */
	vkDestroyPipeline(myDevice, myGraphicsPipeline, nullptr);
	vkDestroyPipelineLayout(myDevice, myPipelineLayout, nullptr);
	vkDestroyBuffer(myDevice, myVertexBuffer, nullptr);
	vkFreeMemory(myDevice, myVertexBufferMemory, nullptr);

	for(auto framebuffer : myFramebuffersVector)
		vkDestroyFramebuffer(myDevice, framebuffer, nullptr);

	vkDestroyRenderPass(myDevice, myRenderPass, nullptr);
	vkDestroyImageView(myDevice, myDepthImageView, nullptr);
	vkDestroyImage(myDevice, myDepthImage, nullptr);
	vkFreeMemory(myDevice, myDepthMemory, nullptr);

	/*
	 * For more informations on the following commands, refer to Demo 01.
	 */
	vkDestroyCommandPool(myDevice, myCommandPool, nullptr);

	for(auto imgView : mySwapchainImageViewsVector)
		vkDestroyImageView(myDevice, imgView, nullptr);

	vkDestroySwapchainKHR(myDevice, mySwapchain, nullptr);
	vkDestroyDevice(myDevice, nullptr);
	vkDestroySurfaceKHR(myInstance, mySurface, nullptr);
	vkdemos::destroyDebugReportCallback(myInstance, myDebugReportCallback);
	vkDestroyInstance(myInstance, nullptr);

	SDL_DestroyWindow(mySdlWindow);
	SDL_Quit();

	return 0;
}
Exemplo n.º 19
0
	PhysicalDeviceProperties::PhysicalDeviceProperties( VkPhysicalDevice device ) {
		vkGetPhysicalDeviceProperties( device, &properties );
		vkGetPhysicalDeviceMemoryProperties( device, &memoryProperties );
	}
Exemplo n.º 20
0
void VulkanContext::ChooseDevice(int physical_device) {
	physical_device_ = physical_device;
	ILOG("Chose physical device %d: %p", physical_device, physical_devices_[physical_device]);

	GetDeviceLayerProperties();
	if (!CheckLayers(device_layer_properties_, device_layer_names_)) {
		WLOG("CheckLayers for device %d failed", physical_device);
	}

	vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr);
	assert(queue_count >= 1);

	queue_props.resize(queue_count);
	vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, queue_props.data());
	assert(queue_count >= 1);

	// Detect preferred formats, in this order.
	static const VkFormat depthStencilFormats[] = {
		VK_FORMAT_D24_UNORM_S8_UINT,
		VK_FORMAT_D32_SFLOAT_S8_UINT,
		VK_FORMAT_D16_UNORM_S8_UINT,
	};
	deviceInfo_.preferredDepthStencilFormat = VK_FORMAT_UNDEFINED;
	for (size_t i = 0; i < ARRAY_SIZE(depthStencilFormats); i++) {
		VkFormatProperties props;
		vkGetPhysicalDeviceFormatProperties(physical_devices_[physical_device_], depthStencilFormats[i], &props);
		if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
			deviceInfo_.preferredDepthStencilFormat = depthStencilFormats[i];
			break;
		}
	}
	if (deviceInfo_.preferredDepthStencilFormat == VK_FORMAT_UNDEFINED) {
		// WTF? This is bad.
		ELOG("Could not find a usable depth stencil format.");
	}

	// This is as good a place as any to do this
	vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties);
	vkGetPhysicalDeviceProperties(physical_devices_[physical_device_], &gpu_props);

	// Optional features
	vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &featuresAvailable_);
	memset(&featuresEnabled_, 0, sizeof(featuresEnabled_));

	// Enable a few safe ones if they are available.
	if (featuresAvailable_.dualSrcBlend) {
		featuresEnabled_.dualSrcBlend = true;
	}
	if (featuresAvailable_.largePoints) {
		featuresEnabled_.largePoints = true;
	}
	if (featuresAvailable_.wideLines) {
		featuresEnabled_.wideLines = true;
	}
	if (featuresAvailable_.geometryShader) {
		featuresEnabled_.geometryShader = true;
	}
	if (featuresAvailable_.logicOp) {
		featuresEnabled_.logicOp = true;
	}
	if (featuresAvailable_.depthClamp) {
		featuresEnabled_.depthClamp = true;
	}
	if (featuresAvailable_.depthBounds) {
		featuresEnabled_.depthBounds = true;
	}
	if (featuresAvailable_.samplerAnisotropy) {
		featuresEnabled_.samplerAnisotropy = true;
	}
	// For easy wireframe mode, someday.
	if (featuresEnabled_.fillModeNonSolid) {
		featuresEnabled_.fillModeNonSolid = true;
	}

	GetDeviceLayerExtensionList(nullptr, device_extension_properties_);

	device_extensions_enabled_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
Exemplo n.º 21
0
void VulkanBase::createInstance() {
    // Application info init
    const VkApplicationInfo applicationInfo = {
        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
        .pNext = NULL,
        .pApplicationName = name.c_str(),
        .applicationVersion = 1,
        .pEngineName = engineName.c_str(),
        .engineVersion = 1,
        .apiVersion = VK_API_VERSION,       //FIXME  Nvidia driver not updated to latest Vulkan Version
    };


    VkInstanceCreateInfo instanceCreateInfo = {
        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
        .pNext = NULL,
        .flags = VK_FLAGS_NONE,
        .pApplicationInfo = &applicationInfo,
        .enabledLayerCount = 0,
        .ppEnabledLayerNames = NULL,
        .enabledExtensionCount = 0,
        .ppEnabledExtensionNames = NULL,
    };

    std::vector<const char*> enabledExtensions = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME};
    //Check if extensions are present
    vkUtils::checkGlobalExtensionPresent(VK_KHR_SURFACE_EXTENSION_NAME);
    vkUtils::checkGlobalExtensionPresent(VK_KHR_XCB_SURFACE_EXTENSION_NAME);

#ifdef _DEBUG
    if (enableValidation) {
        //Extensions management
        enabledExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
        vkUtils::checkGlobalExtensionPresent(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);

        // Layer management
        instanceCreateInfo.enabledLayerCount = vkDebug::validationLayerCount;
        instanceCreateInfo.ppEnabledLayerNames = vkDebug::validationLayerNames;
        // Check standard debug layers are present
        for(uint32_t i = 0; i < instanceCreateInfo.enabledLayerCount; i++) {
            vkUtils::checkGlobalLayerPresent(vkDebug::validationLayerNames[i]);
        }
    }
#endif // DEBUG

    instanceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data();
    instanceCreateInfo.enabledExtensionCount = (uint32_t) enabledExtensions.size();

    CHECK_RESULT(vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
}




void VulkanBase::selectVkPhysicalDevice() {
    uint32_t physicalDeviceCount = 0;
    CHECK_RESULT(vkEnumeratePhysicalDevices(instance,&physicalDeviceCount,nullptr));

    if (physicalDeviceCount<=0) {
        ERROR("No physical device found");
    }

    std::vector<VkPhysicalDevice> physicalDevicesVector(physicalDeviceCount);
    CHECK_RESULT(vkEnumeratePhysicalDevices(instance,&physicalDeviceCount,physicalDevicesVector.data()));

#ifdef _DEBUG
    int deviceIndex = 0;
    for(const auto & phyDev : physicalDevicesVector) {
        VkPhysicalDeviceProperties phyDevProperties;
        vkGetPhysicalDeviceProperties(phyDev, &phyDevProperties);

        std::cout << "--- Physical device: " << phyDevProperties.deviceName << " (index: " << (deviceIndex++) << ")" << std::endl;
        std::cout << "        apiVersion: " << phyDevProperties.apiVersion << std::endl;
        std::cout << "     driverVersion: " << phyDevProperties.driverVersion << std::endl;
        std::cout << "          vendorID: " << phyDevProperties.vendorID << std::endl;
        std::cout << "          deviceID: " << phyDevProperties.deviceID << std::endl;
        std::cout << "        deviceType: ";
        switch(phyDevProperties.deviceType) {
        case VK_PHYSICAL_DEVICE_TYPE_OTHER:
            std::cout << "OTHER";
            break;
        case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
            std::cout << "INTEGRATED_GPU";
            break;
        case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
            std::cout << "DISCRETE_GPU";
            break;
        case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
            std::cout << "VIRTUAL_GPU";
            break;
        case VK_PHYSICAL_DEVICE_TYPE_CPU:
            std::cout << "CPU";
            break;
        default:
            std::cout << "UNKNOWN!!!";
            break;
        }

        std::cout << std::endl;
    }
#endif // _DEBUG

    physicalDevice = physicalDevicesVector.at(0);

    // Gather Physical Device Memory Properties
    vkGetPhysicalDeviceMemoryProperties(physicalDevice,&physicalDeviceMemoryProperties);

}

void VulkanBase::selectQueue() {
    uint32_t queueFamilyPropertyCount = 0;

    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice,&queueFamilyPropertyCount,nullptr);
    if (queueFamilyPropertyCount<=0)
        ERROR("Physical device has no queue families");

    std::vector<VkQueueFamilyProperties> queueFamilyPropertiesVector(queueFamilyPropertyCount);
    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice,&queueFamilyPropertyCount,queueFamilyPropertiesVector.data());

    uint32_t queueFamilyIndex = 0;
    int32_t selectedQueueFamilyIndex = -1;
    VkBool32 presentSupport = VK_FALSE;

#ifdef _DEBUG
    std::cout << std::endl << "--- Number of queue families " << queueFamilyPropertyCount << std::endl;
#endif // _DEBUG

    for(const auto & queueFamProp : queueFamilyPropertiesVector) {
        CHECK_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, swapchain.surface, &presentSupport));
#ifdef _DEBUG
        std::cout << "--- Properties for queue family " << queueFamilyIndex << std::endl;
        std::cout << "                     queueFlags:";

        if(queueFamProp.queueFlags & VK_QUEUE_GRAPHICS_BIT)
            std::cout << " G";
        if(queueFamProp.queueFlags & VK_QUEUE_COMPUTE_BIT)
            std::cout << " C";
        if(queueFamProp.queueFlags & VK_QUEUE_TRANSFER_BIT)
            std::cout << " T";
        if(queueFamProp.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)
            std::cout << " S";

        std::cout << '\n';
        std::cout << "                     queueCount: " << queueFamProp.queueCount << std::endl;
        std::cout << "             timestampValidBits: " << queueFamProp.timestampValidBits << std::endl;
        std::cout << "    minImageTransferGranularity: " << queueFamProp.minImageTransferGranularity.width
                  << ", " << queueFamProp.minImageTransferGranularity.height
                  << ", " << queueFamProp.minImageTransferGranularity.depth
                  << std::endl;

        std::cout << "       Supports present?: " << std::boolalpha << bool(presentSupport) << std::endl << std::endl;
#endif // _DEBUG

        if (bool(queueFamProp.queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport == VK_TRUE) {
            if (selectedQueueFamilyIndex < 0)
                selectedQueueFamilyIndex = queueFamilyIndex;
        }
        queueFamilyIndex++;
    }

    if (selectedQueueFamilyIndex<0)
        ERROR("No queue with both graphics and present capabilities found");

    // Create device after selecting the queue
    std::array<float,1> queuePriorities = {0.0f};

    VkDeviceQueueCreateInfo queueCreateInfo = {
        .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
        .pNext = nullptr,
        .flags = VK_FLAGS_NONE,
        .queueFamilyIndex = (uint32_t) selectedQueueFamilyIndex,
        .queueCount = 1,                            //Number of queues to create
        .pQueuePriorities = queuePriorities.data()
    };

    // Call to createDevice
    createDevice(queueCreateInfo,1);

    //Get a handle to the selected queue
    vkGetDeviceQueue(device, (uint32_t) selectedQueueFamilyIndex, 0, &queue);      //TODO get handle if using multiple queues
    queueFamilyIndex = (uint32_t) selectedQueueFamilyIndex;

}


void VulkanBase::createDevice(VkDeviceQueueCreateInfo requestedQueues, uint32_t requestedQueuesCount) {
    //Check extensions available on the selected physical device before creating it
    // Check swap chain extension
    vkUtils::checkDeviceExtensionPresent(physicalDevice,VK_KHR_SWAPCHAIN_EXTENSION_NAME);
    std::vector<const char*> enabledExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};

    VkDeviceCreateInfo deviceCreateInfo = {
        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
        .pNext = nullptr,
        .flags = VK_FLAGS_NONE,
        .queueCreateInfoCount = requestedQueuesCount,
        .pQueueCreateInfos = &requestedQueues,
        .enabledLayerCount = 0,
        .ppEnabledLayerNames = nullptr,
        .enabledExtensionCount = (uint32_t) enabledExtensions.size(),
        .ppEnabledExtensionNames = enabledExtensions.data(),
        .pEnabledFeatures = NULL
    };

#ifdef _DEBUG
    if (enableValidation) {
        deviceCreateInfo.enabledLayerCount = vkDebug::validationLayerCount;
        deviceCreateInfo.ppEnabledLayerNames = vkDebug::validationLayerNames;
        // Check standard debug layers are present on the device
        for(uint32_t i = 0; i < deviceCreateInfo.enabledLayerCount; i++) {
            vkUtils::checkGlobalLayerPresent(vkDebug::validationLayerNames[i]);
        }
    }
#endif // _DEBUG

    CHECK_RESULT(vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device));
}

void VulkanBase::createCommandPool(const uint32_t queueFamilyIndex, const VkCommandPoolCreateFlagBits createFlagBits) {
    const VkCommandPoolCreateInfo commandPoolCreateInfo= {
        .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
        .pNext = NULL,
        .flags = createFlagBits,
        .queueFamilyIndex = queueFamilyIndex
    };

    CHECK_RESULT(vkCreateCommandPool(device, &commandPoolCreateInfo,nullptr,&commandPool));

#ifdef _DEBUG
    std::cout << "\n+++ Created command pool" << std::endl;
#endif // _DEBUG
}

void VulkanBase::createSynchroItems()
{
    // Semaphores

    VkSemaphoreCreateInfo semaphoreCreateInfo = {
        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
        .pNext = NULL,
        .flags = VK_FLAGS_NONE
    };

    // Semaphore signaled on swapchain image ready to use and wait on the queue before rendering/present
    CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAcquiredSemaphore));

    // Semaphore signaled on queue rendering termination and waited on present operation
    CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &renderingCompletedSemaphore));

    // Fences

    VkFenceCreateInfo fenceCreateInfo = {
        .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
        .pNext = NULL,
        .flags = VK_FLAGS_NONE
    };

    CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &presentFence));

    #ifdef _DEBUG
    std::cout << "\n+++ Created semaphores and fences\n";
    #endif // _DEBUG
}



void VulkanBase::createCommandBuffers(VkCommandBuffer* cmdBuffer, uint32_t commandBufferCount, VkCommandBufferLevel cmdBufferLevel)
{
    const VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
        .pNext = NULL,
        .commandPool = commandPool,
        .level = cmdBufferLevel,
        .commandBufferCount = commandBufferCount
    };

    CHECK_RESULT(vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, cmdBuffer));

    #ifdef _DEBUG
    std::cout << "\n+++ Allocated " << commandBufferCount << " command buffers" << std::endl;
    #endif // _DEBUG
}

void VulkanBase::setupInitCommandBuffer()
{
    VkCommandBufferBeginInfo commandBufferBeginInfo = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
        .pNext = NULL,
        .flags = VK_FLAGS_NONE,
        .pInheritanceInfo = NULL
    };

    CHECK_RESULT(vkBeginCommandBuffer(initCommandBuffer, &commandBufferBeginInfo));

    // Creates an image memory barrier to change the layout for every image on the swapchain
    VkImageMemoryBarrier imageMemoryBarrier = {
        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
        .pNext = NULL,
        .srcAccessMask = VK_FLAGS_NONE,
        .dstAccessMask = VK_FLAGS_NONE,
        .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
        .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
        .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .image = 0,
        .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}
    };


	// Pipeline Barrier for each swapchain image
    for (const auto& image: swapchain.swapchainImagesVector){
        imageMemoryBarrier.image = image;

        vkCmdPipelineBarrier(initCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, //Put barrier on top of the pipeline
        VK_FLAGS_NONE,
        0, nullptr,                 // memoryBarrier
        0, nullptr,                 // bufferMemoryBarrier
        1, &imageMemoryBarrier);    // imageMemoryBarrier
    }

    CHECK_RESULT(vkEndCommandBuffer(initCommandBuffer));

    #ifdef _DEBUG
    std::cout << "\n+++ Finished recording initCommandBuffer\n";
    #endif // _DEBUG
}

void VulkanBase::setupPresentCommandBuffer(const VkImage currentSwapchainImage, const float* clearColors)
{

 VkCommandBufferBeginInfo commandBufferBeginInfo = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
        .pNext = NULL,
        .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
        .pInheritanceInfo = NULL
    };

    CHECK_RESULT(vkBeginCommandBuffer(presentCommandBuffer, &commandBufferBeginInfo));

    VkImageMemoryBarrier imageMemoryBarrier = {
        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
        .pNext = NULL,
        .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT,
        .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
        .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
        .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
        .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
        .image = currentSwapchainImage,
        .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}
    };

    //Set barrier on top to change layout and access
    vkCmdPipelineBarrier(presentCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
    VK_FLAGS_NONE, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);

    VkClearColorValue clearColorValue;
    VkImageSubresourceRange imageSubresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};

    clearColorValue.float32[0] = clearColors[0];
    clearColorValue.float32[1] = clearColors[1];
    clearColorValue.float32[2] = clearColors[2];
    clearColorValue.float32[3] = 1.0f;

    // Command to clear the swapchain image
    vkCmdClearColorImage(presentCommandBuffer,currentSwapchainImage,
    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColorValue, 1, &imageSubresourceRange);

    /*
	 * Transition the swapchain image from VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
	 * to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
	 */
	imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
	imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
	imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
	imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;

    // Set barrier end of pipeline
	vkCmdPipelineBarrier(presentCommandBuffer,
		VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
		0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier
	);

    CHECK_RESULT(vkEndCommandBuffer(presentCommandBuffer));

    #ifdef _DEBUG
    //std::cout << "\n+++ Finished recording presentCommandBuffer\n";
    #endif // _DEBUG
}

void VulkanBase::renderFrame(const float* clearColors)
{
    // Wait on previous frame fence (render too fast)
    //CHECK_RESULT(vkWaitForFences(device, 1, &presentFence, VK_TRUE, UINT64_MAX));
    //CHECK_RESULT(vkResetFences(device, 1, &presentFence));

    // Acquire next image on the swapchain
    uint32_t imageIndex = UINT64_MAX;
    CHECK_RESULT(vkAcquireNextImageKHR(device, swapchain.swapchain, UINT64_MAX, imageAcquiredSemaphore, VK_NULL_HANDLE, &imageIndex));

    // Setup the present command buffer
    setupPresentCommandBuffer(swapchain.swapchainImagesVector.at(imageIndex),clearColors);
    // Submit present command buffer to the queue
    // Waits on imageAcquiredSemaphore so it doesnt start rendering until the image from the swapchain is ready and
    // it also signals the renderingCompletedSemaphore used by the later present

    VkPipelineStageFlags pipelineStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    VkSubmitInfo submitInfo = {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
        .pNext = NULL,
        .waitSemaphoreCount = 1,
        .pWaitSemaphores = &imageAcquiredSemaphore,
        .pWaitDstStageMask = &pipelineStageFlags,
        .commandBufferCount = 1,
        .pCommandBuffers = &presentCommandBuffer,
        .signalSemaphoreCount = 1,
        .pSignalSemaphores = &renderingCompletedSemaphore
    };

    CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));

    // Present the rendered image
    VkPresentInfoKHR presentInfo = {
        .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
        .pNext = NULL,
        .waitSemaphoreCount = 1,
        .pWaitSemaphores = &renderingCompletedSemaphore,
        .swapchainCount = 1,
        .pSwapchains = &swapchain.swapchain,
        .pImageIndices = &imageIndex,
        .pResults = nullptr
    };

    CHECK_RESULT(vkQueuePresentKHR(queue,&presentInfo));

    CHECK_RESULT(vkQueueWaitIdle(queue)); //TODO Not sure this is the correct way...


}



void VulkanBase::prepare()
{
    //Allocate command Buffers
    createCommandBuffers(&initCommandBuffer, 1, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
    createCommandBuffers(&presentCommandBuffer, 1, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
    commandBuffersVector.push_back(initCommandBuffer);
    commandBuffersVector.push_back(presentCommandBuffer);
    //Initialize command Buffers
    setupInitCommandBuffer();
    // Submit initialization command buffer to the queue
    VkSubmitInfo submitInfo = {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
        .pNext = nullptr,
        .waitSemaphoreCount = 0,
        .pWaitSemaphores = nullptr,
        .pWaitDstStageMask = VK_FLAGS_NONE,
        .commandBufferCount = 1,
        .pCommandBuffers = &initCommandBuffer,
        .signalSemaphoreCount = 0,
        .pSignalSemaphores = nullptr
    };

    CHECK_RESULT(vkQueueSubmit(queue,1,&submitInfo, VK_NULL_HANDLE));

    CHECK_RESULT(vkQueueWaitIdle(queue));

    vkFreeCommandBuffers(device, commandPool, 1, &initCommandBuffer);

#ifdef _DEBUG
    std::cout << "\n+++ initCommandBuffer work complete!\n";
    std::cout << "\n******* Rendering Start ******\n";
#endif // _DEBUG

}
Exemplo n.º 22
0
void VulkanExampleBase::initVulkan(bool enableValidation)
{
	VkResult err;

	// Vulkan instance
	err = createInstance(enableValidation);
	if (err)
	{
		vkTools::exitFatal("Could not create Vulkan instance : \n" + vkTools::errorString(err), "Fatal error");
	}

#if defined(__ANDROID__)
	loadVulkanFunctions(instance);
#endif

	// Physical device
	uint32_t gpuCount = 0;
	// Get number of available physical devices
	err = vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr);
	assert(!err);
	assert(gpuCount > 0);
	// Enumerate devices
	std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
	err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
	if (err)
	{
		vkTools::exitFatal("Could not enumerate phyiscal devices : \n" + vkTools::errorString(err), "Fatal error");
	}

	// Note :
	// This example will always use the first physical device reported,
	// change the vector index if you have multiple Vulkan devices installed
	// and want to use another one
	physicalDevice = physicalDevices[0];

	// Find a queue that supports graphics operations
	uint32_t graphicsQueueIndex = 0;
	uint32_t queueCount;
	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL);
	assert(queueCount >= 1);

	std::vector<VkQueueFamilyProperties> queueProps;
	queueProps.resize(queueCount);
	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data());

	for (graphicsQueueIndex = 0; graphicsQueueIndex < queueCount; graphicsQueueIndex++)
	{
		if (queueProps[graphicsQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT)
			break;
	}
	assert(graphicsQueueIndex < queueCount);

	// Vulkan device
	std::array<float, 1> queuePriorities = { 0.0f };
	VkDeviceQueueCreateInfo queueCreateInfo = {};
	queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
	queueCreateInfo.queueFamilyIndex = graphicsQueueIndex;
	queueCreateInfo.queueCount = 1;
	queueCreateInfo.pQueuePriorities = queuePriorities.data();

	err = createDevice(queueCreateInfo, enableValidation);
	assert(!err);

	// Store properties (including limits) and features of the phyiscal device
	// So examples can check against them and see if a feature is actually supported
	vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
	vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);

#if defined(__ANDROID__)
	LOGD(deviceProperties.deviceName);
#endif

	// Gather physical device memory properties
	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);

	// Get the graphics queue
	vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);

	// Find a suitable depth format
	VkBool32 validDepthFormat = vkTools::getSupportedDepthFormat(physicalDevice, &depthFormat);
	assert(validDepthFormat);

	swapChain.connect(instance, physicalDevice, device);

	// Create synchronization objects
	VkSemaphoreCreateInfo semaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo();
	// Create a semaphore used to synchronize image presentation
	// Ensures that the image is displayed before we start submitting new commands to the queu
	err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.presentComplete);
	assert(!err);
	// Create a semaphore used to synchronize command submission
	// Ensures that the image is not presented until all commands have been sumbitted and executed
	err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.renderComplete);
	assert(!err);

	// Set up submit info structure
	// Semaphores will stay the same during application lifetime
	// Command buffer submission info is set by each example
	submitInfo = vkTools::initializers::submitInfo();
	submitInfo.pWaitDstStageMask = &submitPipelineStages;
	submitInfo.waitSemaphoreCount = 1;
	submitInfo.pWaitSemaphores = &semaphores.presentComplete;
	submitInfo.signalSemaphoreCount = 1;
	submitInfo.pSignalSemaphores = &semaphores.renderComplete;
}
Exemplo n.º 23
0
int main(void) {
    VkInstance instance;
    {
        const char debug_ext[] = "VK_EXT_debug_report";
        const char* extensions[] = {debug_ext,};

        const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation";
        const char* layers[] = {validation_layer,};

        VkInstanceCreateInfo create_info = {
            .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .pApplicationInfo = NULL,
            .enabledLayerCount = NELEMS(layers),
            .ppEnabledLayerNames = layers,
            .enabledExtensionCount = NELEMS(extensions),
            .ppEnabledExtensionNames = extensions,
        };
        assert(vkCreateInstance(&create_info, NULL, &instance) == VK_SUCCESS);
    }

    VkDebugReportCallbackEXT debug_callback;
    {
        VkDebugReportCallbackCreateInfoEXT create_info = {
            .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
            .pNext = NULL,
            .flags = (VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
                      VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT),
            .pfnCallback = &debugReportCallback,
            .pUserData = NULL,
        };

        PFN_vkCreateDebugReportCallbackEXT createDebugReportCallback =
            (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
        assert(createDebugReportCallback);
        assert(createDebugReportCallback(instance, &create_info, NULL, &debug_callback) == VK_SUCCESS);
    }

    VkPhysicalDevice phy_device;
    {
        uint32_t num_devices;
        assert(vkEnumeratePhysicalDevices(instance, &num_devices, NULL) == VK_SUCCESS);
        assert(num_devices >= 1);
        VkPhysicalDevice * phy_devices = malloc(sizeof(*phy_devices) * num_devices);
        assert(vkEnumeratePhysicalDevices(instance, &num_devices, phy_devices) == VK_SUCCESS);
        phy_device = phy_devices[0];
        free(phy_devices);
    }

    VkPhysicalDeviceMemoryProperties memory_properties;
    vkGetPhysicalDeviceMemoryProperties(phy_device, &memory_properties);

    VkDevice device;
    {
        float queue_priorities[] = {1.0};
        const char validation_layer[] = "VK_LAYER_LUNARG_standard_validation";
        const char* layers[] = {validation_layer,};

        uint32_t nqueues;
        matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, NULL);
        assert(nqueues > 0);
        uint32_t * queue_family_idxs = malloc(sizeof(*queue_family_idxs) * nqueues);
        matchingQueues(phy_device, VK_QUEUE_GRAPHICS_BIT, &nqueues, queue_family_idxs);

        VkDeviceQueueCreateInfo queue_info = {
            .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .queueFamilyIndex = queue_family_idxs[0],
            .queueCount = 1,
            .pQueuePriorities = queue_priorities,
        };
        free(queue_family_idxs);

        VkPhysicalDeviceFeatures features = {
            .geometryShader = VK_TRUE,
            .fillModeNonSolid = VK_TRUE,
        };

        VkDeviceCreateInfo create_info = {
            .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .queueCreateInfoCount = 1,
            .pQueueCreateInfos = &queue_info,
            .enabledLayerCount = NELEMS(layers),
            .ppEnabledLayerNames = layers,
            .enabledExtensionCount = 0,
            .ppEnabledExtensionNames = NULL,
            .pEnabledFeatures = &features,
        };

        assert(vkCreateDevice(phy_device, &create_info, NULL, &device) == VK_SUCCESS);
    }

    VkQueue queue;
    vkGetDeviceQueue(device, 0, 0, &queue);

    VkCommandPool cmd_pool;
    {
        VkCommandPoolCreateInfo create_info = {
            .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
            .pNext = NULL,
            .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
            .queueFamilyIndex = 0,
        };
        assert(vkCreateCommandPool(device, &create_info, NULL, &cmd_pool) == VK_SUCCESS);
    }

    VkRenderPass render_pass;
    {
        VkAttachmentDescription attachments[] = {{
                .flags = 0,
                .format = VK_FORMAT_R8G8B8A8_UNORM,
                .samples = VK_SAMPLE_COUNT_8_BIT,
                .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
                .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
                .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
                .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
                .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
                .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
            }, {
                .flags = 0,
                .format = VK_FORMAT_D16_UNORM,
                .samples = VK_SAMPLE_COUNT_8_BIT,
                .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
                .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
                .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
                .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
                .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
                .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
            }, {
                .flags = 0,
                .format = VK_FORMAT_R8G8B8A8_UNORM,
                .samples = VK_SAMPLE_COUNT_1_BIT,
                .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
                .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
                .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
                .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
                .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
                .finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
            }};
        VkAttachmentReference attachment_refs[NELEMS(attachments)] = {{
                .attachment = 0,
                .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
            }, {
                .attachment = 1,
                .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
            }, {
                .attachment = 2,
                .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
            }};
        VkSubpassDescription subpasses[1] = {{
                .flags = 0,
                .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
                .inputAttachmentCount = 0,
                .pInputAttachments = NULL,
                .colorAttachmentCount = 1,
                .pColorAttachments = &attachment_refs[0],
                .pResolveAttachments = &attachment_refs[2],
                .pDepthStencilAttachment = &attachment_refs[1],
                .preserveAttachmentCount = 0,
                .pPreserveAttachments = NULL,
            }};
        VkSubpassDependency dependencies[] = {{
                .srcSubpass = 0,
                .dstSubpass = VK_SUBPASS_EXTERNAL,
                .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT,
                .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
                .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
                .dependencyFlags = 0,
            }};
        VkRenderPassCreateInfo create_info = {
            .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .attachmentCount = NELEMS(attachments),
            .pAttachments = attachments,
            .subpassCount = NELEMS(subpasses),
            .pSubpasses = subpasses,
            .dependencyCount = NELEMS(dependencies),
            .pDependencies = dependencies,
        };
        assert(vkCreateRenderPass(device, &create_info, NULL, &render_pass) == VK_SUCCESS);
    }

    VkImage images[3];
    VkDeviceMemory image_memories[NELEMS(images)];
    VkImageView views[NELEMS(images)];
    createFrameImage(memory_properties, device, render_size,
                     VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_8_BIT,
                     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
                     &images[0], &image_memories[0], &views[0]);
    createFrameImage(memory_properties, device, render_size,
                     VK_FORMAT_D16_UNORM, VK_SAMPLE_COUNT_8_BIT,
                     VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_ASPECT_DEPTH_BIT,
                     &images[1], &image_memories[1], &views[1]);
    createFrameImage(memory_properties, device, render_size,
                     VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT,
                     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
                     VK_IMAGE_ASPECT_COLOR_BIT,
                     &images[2], &image_memories[2], &views[2]);

    VkBuffer verts_buffer;
    VkDeviceMemory verts_memory;
    createBuffer(memory_properties, device, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, sizeof(verts), verts, &verts_buffer, &verts_memory);

    VkBuffer index_buffer;
    VkDeviceMemory index_memory;
    createBuffer(memory_properties, device, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, sizeof(indices), indices, &index_buffer, &index_memory);

    VkBuffer image_buffer;
    VkDeviceMemory image_buffer_memory;
    createBuffer(memory_properties, device, VK_BUFFER_USAGE_TRANSFER_DST_BIT, render_size.height * render_size.width * 4, NULL, &image_buffer, &image_buffer_memory);

    VkFramebuffer framebuffer;
    createFramebuffer(device, render_size, 3, views, render_pass, &framebuffer);

    VkShaderModule shaders[5];
    {
        char* filenames[NELEMS(shaders)] = {"cube.vert.spv", "cube.geom.spv", "cube.frag.spv", "wireframe.geom.spv", "color.frag.spv"};
        for (size_t i = 0; i < NELEMS(shaders); i++){
            size_t code_size;
            uint32_t * code;
            assert((code_size = loadModule(filenames[i], &code)) != 0);

            VkShaderModuleCreateInfo create_info = {
                .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
                .pNext = NULL,
                .flags = 0,
                .codeSize = code_size,
                .pCode = code,
            };
            assert(vkCreateShaderModule(device, &create_info, NULL, &shaders[i]) == VK_SUCCESS);
            free(code);
        }
    }

    VkPipelineLayout pipeline_layout;
    {
        VkPushConstantRange push_range = {
            .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
            .offset = 0,
            .size = 4,
        };
        VkPipelineLayoutCreateInfo create_info = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .setLayoutCount = 0,
            .pSetLayouts = NULL,
            .pushConstantRangeCount = 1,
            .pPushConstantRanges = &push_range,
        };
        assert(vkCreatePipelineLayout(device, &create_info, NULL, &pipeline_layout) == VK_SUCCESS);
    }

    VkPipeline pipelines[2];
    {
        VkPipelineShaderStageCreateInfo stages[3] = {{
                .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
                .pNext = NULL,
                .flags = 0,
                .stage = VK_SHADER_STAGE_VERTEX_BIT,
                .module = shaders[0],
                .pName = "main",
                .pSpecializationInfo = NULL,
            },{
                .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
                .pNext = NULL,
                .flags = 0,
                .stage = VK_SHADER_STAGE_GEOMETRY_BIT,
                .module = shaders[1],
                .pName = "main",
                .pSpecializationInfo = NULL,
            },{
                .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
                .pNext = NULL,
                .flags = 0,
                .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
                .module = shaders[2],
                .pName = "main",
                .pSpecializationInfo = NULL,
            }};
        VkVertexInputBindingDescription vtx_binding = {
            .binding = 0,
            .stride = sizeof(struct Vertex),
            .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
        };
        VkVertexInputAttributeDescription vtx_attr = {
            .location = 0,
            .binding = 0,
            .format = VK_FORMAT_R32G32B32_SFLOAT,
            .offset = offsetof(struct Vertex, pos),
        };
        VkPipelineVertexInputStateCreateInfo vtx_state = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .vertexBindingDescriptionCount = 1,
            .pVertexBindingDescriptions = &vtx_binding,
            .vertexAttributeDescriptionCount = 1,
            .pVertexAttributeDescriptions = &vtx_attr,
        };
        VkPipelineInputAssemblyStateCreateInfo ia_state = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
            .primitiveRestartEnable = VK_TRUE,
        };
        VkViewport viewport = {
            .x = 0,
            .y = 0,
            .width = render_size.width,
            .height = render_size.height,
            .minDepth = 0.0,
            .maxDepth = 1.0,
        };
        VkRect2D scissor= {
            .offset = {.x = 0, .y = 0,},
            .extent = render_size,
        };
        VkPipelineViewportStateCreateInfo viewport_state = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .viewportCount = 1,
            .pViewports = &viewport,
            .scissorCount = 1,
            .pScissors = &scissor,
        };
        VkPipelineRasterizationStateCreateInfo rasterization_state = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .depthClampEnable = VK_FALSE,
            .rasterizerDiscardEnable = VK_FALSE,
            .polygonMode = VK_POLYGON_MODE_FILL,
            .cullMode = VK_CULL_MODE_NONE,
            .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
            .depthBiasEnable = VK_FALSE,
            .lineWidth = 1.0,
        };
        VkPipelineMultisampleStateCreateInfo multisample_state = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .rasterizationSamples = VK_SAMPLE_COUNT_8_BIT,
            .sampleShadingEnable = VK_FALSE,
            .minSampleShading = 0.0,
            .pSampleMask = NULL,
            .alphaToCoverageEnable = VK_FALSE,
            .alphaToOneEnable = VK_FALSE,
        };
        VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .depthTestEnable = VK_TRUE,
            .depthWriteEnable = VK_TRUE,
            .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL,
            .depthBoundsTestEnable = VK_FALSE,
            .stencilTestEnable = VK_FALSE,
            .front = {},
            .back = {},
            .minDepthBounds = 0.0,
            .maxDepthBounds = 1.0,
        };
        VkPipelineColorBlendAttachmentState color_blend_attachment = {
            .blendEnable = VK_FALSE,
            .colorWriteMask = ( VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
                                | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT),
        };
        VkPipelineColorBlendStateCreateInfo color_blend_state = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .logicOpEnable = VK_FALSE, //.logicOp = 0,
            .attachmentCount = 1,
            .pAttachments = &color_blend_attachment,
            .blendConstants = {},
        };

        VkGraphicsPipelineCreateInfo create_info = {
            .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
            .pNext = NULL,
            .flags = 0,
            .stageCount = NELEMS(stages),
            .pStages = stages,
            .pVertexInputState = &vtx_state,
            .pInputAssemblyState = &ia_state,
            .pTessellationState = NULL,
            .pViewportState = &viewport_state,
            .pRasterizationState = &rasterization_state,
            .pMultisampleState = &multisample_state,
            .pDepthStencilState = &depth_stencil_state,
            .pColorBlendState = &color_blend_state,
            .pDynamicState = NULL,
            .layout = pipeline_layout,
            .renderPass = render_pass,
            .subpass = 0,
            .basePipelineHandle = VK_NULL_HANDLE,
            .basePipelineIndex = 0,
        };
        assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[0]) == VK_SUCCESS);
        stages[1].module = shaders[3];
        stages[2].module = shaders[4];
        rasterization_state.polygonMode = VK_POLYGON_MODE_LINE;
        assert(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipelines[1]) == VK_SUCCESS);
    }

    VkCommandBuffer draw_buffers[2];
    {
        VkCommandBufferAllocateInfo allocate_info = {
            .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
            .pNext = NULL,
            .commandPool = cmd_pool,
            .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
            .commandBufferCount = NELEMS(draw_buffers),
        };
        assert(vkAllocateCommandBuffers(device, &allocate_info, draw_buffers) == VK_SUCCESS);
    }

    {
        VkCommandBufferBeginInfo begin_info = {
            .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            .pNext = NULL,
            .flags = 0,
            .pInheritanceInfo = NULL,
        };

        VkClearValue clear_values[] = {{
                .color.float32 = {0.0, 0.0, 0.0, 1.0},
            }, {
                .depthStencil = {.depth = 1.0},
            }};
        VkRenderPassBeginInfo renderpass_begin_info = {
            .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
            .pNext = NULL,
            .renderPass = render_pass,
            .framebuffer = framebuffer,
            .renderArea = {
                .offset = {.x = 0, .y = 0},
                .extent = render_size,
            },
            .clearValueCount = NELEMS(clear_values),
            .pClearValues = clear_values,
        };
        for (size_t i = 0; i < NELEMS(draw_buffers); i++){
            assert(vkBeginCommandBuffer(draw_buffers[i], &begin_info) == VK_SUCCESS);
            uint32_t persp = i == 0;
            vkCmdPushConstants(draw_buffers[i], pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(persp), &persp);
            vkCmdBeginRenderPass(draw_buffers[i], &renderpass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
            VkDeviceSize offset = 0;
            vkCmdBindVertexBuffers(draw_buffers[i], 0, 1, &verts_buffer, &offset);
            vkCmdBindIndexBuffer(draw_buffers[i], index_buffer, 0, VK_INDEX_TYPE_UINT32);
            for (size_t j = 0; j < NELEMS(pipelines); j++) {
                vkCmdBindPipeline(draw_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[j]);
                vkCmdDrawIndexed(draw_buffers[i], 20, 27, 0, 0, 0);
            }
            vkCmdEndRenderPass(draw_buffers[i]);
        }

        VkBufferImageCopy copy = {
            .bufferOffset = 0,
            .bufferRowLength = 0, // Tightly packed
            .bufferImageHeight = 0, // Tightly packed
            .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
            .imageOffset = {0, 0, 0},
            .imageExtent = {.width = render_size.width,
                            .height = render_size.height,
                            .depth = 1},
        };
        VkBufferMemoryBarrier transfer_barrier = {
            .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
            .pNext = 0,
            .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
            .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
            .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
            .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
            .buffer = image_buffer,
            .offset = 0,
            .size = VK_WHOLE_SIZE,
        };
        for (size_t i = 0; i < NELEMS(draw_buffers); i++){
            vkCmdCopyImageToBuffer(draw_buffers[i], images[2], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image_buffer, 1, &copy);

            vkCmdPipelineBarrier(draw_buffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, &transfer_barrier, 0, NULL);
            assert(vkEndCommandBuffer(draw_buffers[i]) == VK_SUCCESS);
        }
    }

    VkFence fence;
    {
        VkFenceCreateInfo create_info = {
            .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
            .pNext = 0,
            .flags = 0,
        };
        assert(vkCreateFence(device, &create_info, NULL, &fence) == VK_SUCCESS);
    }

    {
        char * filenames[] = {"cube_persp.tif", "cube_ortho.tif"};
        char * image_data;
        assert(vkMapMemory(device, image_buffer_memory, 0, VK_WHOLE_SIZE, 0, (void **) &image_data) == VK_SUCCESS);
        VkMappedMemoryRange image_flush = {
            .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, .pNext = NULL,
            .memory = image_buffer_memory,
            .offset = 0,
            .size = VK_WHOLE_SIZE,
        };

        VkSubmitInfo submit_info = {
            .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
            .pNext = NULL,
            .waitSemaphoreCount = 0,
            .pWaitSemaphores = NULL,
            .pWaitDstStageMask = NULL,
            .commandBufferCount = 1,
            .pCommandBuffers = NULL,
            .signalSemaphoreCount = 0,
            .pSignalSemaphores = NULL,
        };

        for (size_t i = 0; i < NELEMS(filenames); i++){
            submit_info.pCommandBuffers = &draw_buffers[i];
            assert(vkResetFences(device, 1, &fence) == VK_SUCCESS);
            assert(vkQueueSubmit(queue, 1, &submit_info, fence) == VK_SUCCESS);
            assert(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX) == VK_SUCCESS);
            assert(vkInvalidateMappedMemoryRanges(device, 1, &image_flush) == VK_SUCCESS);
            assert(writeTiff(filenames[i], image_data, render_size, nchannels) == 0);
        }

        vkUnmapMemory(device, image_buffer_memory);
    }

    assert(vkQueueWaitIdle(queue) == VK_SUCCESS);
    vkDestroyFence(device, fence, NULL);

    vkDestroyFramebuffer(device, framebuffer, NULL);
    for (size_t i = 0; i < NELEMS(images); i++){
        vkDestroyImage(device, images[i], NULL);
        vkDestroyImageView(device, views[i], NULL);
        vkFreeMemory(device, image_memories[i], NULL);
    }

    vkDestroyBuffer(device, image_buffer, NULL);
    vkFreeMemory(device, image_buffer_memory, NULL);

    vkDestroyBuffer(device, verts_buffer, NULL);
    vkFreeMemory(device, verts_memory, NULL);

    vkDestroyBuffer(device, index_buffer, NULL);
    vkFreeMemory(device, index_memory, NULL);

    for (size_t i = 0; i < NELEMS(pipelines); i++){
        vkDestroyPipeline(device, pipelines[i], NULL);
    }
    vkDestroyPipelineLayout(device, pipeline_layout, NULL);
    for(size_t i = 0; i < NELEMS(shaders); i++)
        vkDestroyShaderModule(device, shaders[i], NULL);

    vkDestroyRenderPass(device, render_pass, NULL);
    vkFreeCommandBuffers(device, cmd_pool, NELEMS(draw_buffers), draw_buffers);
    vkDestroyCommandPool(device, cmd_pool, NULL);
    vkDestroyDevice(device, NULL);
    {
        PFN_vkDestroyDebugReportCallbackEXT destroyDebugReportCallback =
            (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
        assert(destroyDebugReportCallback);
        destroyDebugReportCallback(instance, debug_callback, NULL);
    }
    vkDestroyInstance(instance, NULL);
    return 0;
}