/* Helper function which stores wrapped physical devices in the instance object. */ static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *instance) { VkResult res; struct VkPhysicalDevice_T **tmp_phys_devs; uint32_t num_phys_devs = 0; unsigned int i; res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, NULL); if (res != VK_SUCCESS) { ERR("Failed to enumerate physical devices, res=%d\n", res); return res; } /* Don't bother with any of the rest if the system just lacks devices. */ if (num_phys_devs == 0) return VK_SUCCESS; tmp_phys_devs = heap_calloc(num_phys_devs, sizeof(*tmp_phys_devs)); if (!tmp_phys_devs) return VK_ERROR_OUT_OF_HOST_MEMORY; res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, tmp_phys_devs); if (res != VK_SUCCESS) { heap_free(tmp_phys_devs); return res; } instance->phys_devs = heap_calloc(num_phys_devs, sizeof(*instance->phys_devs)); if (!instance->phys_devs) { heap_free(tmp_phys_devs); return VK_ERROR_OUT_OF_HOST_MEMORY; } /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */ for (i = 0; i < num_phys_devs; i++) { struct VkPhysicalDevice_T *phys_dev = wine_vk_physical_device_alloc(instance, tmp_phys_devs[i]); if (!phys_dev) { ERR("Unable to allocate memory for physical device!\n"); heap_free(tmp_phys_devs); return VK_ERROR_OUT_OF_HOST_MEMORY; } instance->phys_devs[i] = phys_dev; instance->num_phys_devs = i + 1; } instance->num_phys_devs = num_phys_devs; heap_free(tmp_phys_devs); return VK_SUCCESS; }
VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t count, const VkSubmitInfo *submits, VkFence fence) { VkSubmitInfo *submits_host; VkResult res; VkCommandBuffer *command_buffers; unsigned int i, j, num_command_buffers; TRACE("%p %u %p 0x%s\n", queue, count, submits, wine_dbgstr_longlong(fence)); if (count == 0) { return queue->device->funcs.p_vkQueueSubmit(queue->queue, 0, NULL, fence); } submits_host = heap_calloc(count, sizeof(*submits_host)); if (!submits_host) { ERR("Unable to allocate memory for submit buffers!\n"); return VK_ERROR_OUT_OF_HOST_MEMORY; } for (i = 0; i < count; i++) { memcpy(&submits_host[i], &submits[i], sizeof(*submits_host)); num_command_buffers = submits[i].commandBufferCount; command_buffers = heap_calloc(num_command_buffers, sizeof(*submits_host)); if (!command_buffers) { ERR("Unable to allocate memory for comman buffers!\n"); res = VK_ERROR_OUT_OF_HOST_MEMORY; goto err; } for (j = 0; j < num_command_buffers; j++) { command_buffers[j] = submits[i].pCommandBuffers[j]->command_buffer; } submits_host[i].pCommandBuffers = command_buffers; } res = queue->device->funcs.p_vkQueueSubmit(queue->queue, count, submits_host, fence); err: for (i = 0; i < count; i++) { heap_free((void *)submits_host[i].pCommandBuffers); } heap_free(submits_host); TRACE("Returning %d\n", res); return res; }
/* Helper function to create queues for a given family index. */ static struct VkQueue_T *wine_vk_device_alloc_queues(struct VkDevice_T *device, uint32_t family_index, uint32_t queue_count) { struct VkQueue_T *queues; unsigned int i; if (!(queues = heap_calloc(queue_count, sizeof(*queues)))) { ERR("Failed to allocate memory for queues\n"); return NULL; } for (i = 0; i < queue_count; i++) { struct VkQueue_T *queue = &queues[i]; queue->device = device; /* The native device was already allocated with the required number of queues, * so just fetch them from there. */ device->funcs.p_vkGetDeviceQueue(device->device, family_index, i, &queue->queue); /* Set special header for ICD loader. */ queue->base.loader_magic = VULKAN_ICD_MAGIC_VALUE; } return queues; }
void *zalloc( size_t size ) { if(global_heap_ptr) { return heap_calloc(global_heap_ptr, 1, size); } return ::calloc(1, size); }
void *calloc( size_t elt_size, size_t size ) { if(global_heap_ptr) { return heap_calloc(global_heap_ptr, elt_size, size); } return ::calloc(elt_size, size); }
VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name, uint32_t *count, VkExtensionProperties *properties) { VkResult res; uint32_t num_properties = 0, num_host_properties = 0; VkExtensionProperties *host_properties = NULL; unsigned int i, j; TRACE("%p %p %p\n", layer_name, count, properties); /* This shouldn't get called with layer_name set, the ICD loader prevents it. */ if (layer_name) { ERR("Layer enumeration not supported from ICD.\n"); return VK_ERROR_LAYER_NOT_PRESENT; } res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, NULL); if (res != VK_SUCCESS) return res; host_properties = heap_calloc(num_host_properties, sizeof(*host_properties)); if (!host_properties) return VK_ERROR_OUT_OF_HOST_MEMORY; res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, host_properties); if (res != VK_SUCCESS) { ERR("Failed to retrieve host properties, res=%d\n", res); heap_free(host_properties); return res; } /* The Wine graphics driver provides us with all extensions supported by the host side * including extension fixup (e.g. VK_KHR_xlib_surface -> VK_KHR_win32_surface). It is * up to us here to filter the list down to extensions for which we have thunks. */ for (i = 0; i < num_host_properties; i++) { if (wine_vk_instance_extension_supported(host_properties[i].extensionName)) num_properties++; else TRACE("Instance extension '%s' is not supported.\n", host_properties[i].extensionName); } if (!properties) { TRACE("Returning %u extensions\n", num_properties); *count = num_properties; heap_free(host_properties); return VK_SUCCESS; } for (i = 0, j = 0; i < num_host_properties && j < *count; i++) { if (wine_vk_instance_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s'\n", host_properties[i].extensionName); properties[j] = host_properties[i]; j++; } } *count = min(*count, num_properties); heap_free(host_properties); return *count < num_properties ? VK_INCOMPLETE : VK_SUCCESS; }
static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstance_T *instance, VkPhysicalDevice phys_dev) { struct VkPhysicalDevice_T *object; uint32_t num_host_properties, num_properties = 0; VkExtensionProperties *host_properties = NULL; VkResult res; unsigned int i, j; if (!(object = heap_alloc_zero(sizeof(*object)))) return NULL; object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE; object->instance = instance; object->phys_dev = phys_dev; res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &num_host_properties, NULL); if (res != VK_SUCCESS) { ERR("Failed to enumerate device extensions, res=%d\n", res); goto err; } host_properties = heap_calloc(num_host_properties, sizeof(*host_properties)); if (!host_properties) { ERR("Failed to allocate memory for device properties!\n"); goto err; } res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &num_host_properties, host_properties); if (res != VK_SUCCESS) { ERR("Failed to enumerate device extensions, res=%d\n", res); goto err; } /* Count list of extensions for which we have an implementation. * TODO: perform translation for platform specific extensions. */ for (i = 0; i < num_host_properties; i++) { if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object); num_properties++; } else { TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties[i].extensionName); } } TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties); if (!(object->extensions = heap_calloc(num_properties, sizeof(*object->extensions)))) { ERR("Failed to allocate memory for device extensions!\n"); goto err; } for (i = 0, j = 0; i < num_host_properties; i++) { if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { object->extensions[j] = host_properties[i]; j++; } } object->extension_count = num_properties; heap_free(host_properties); return object; err: wine_vk_physical_device_free(object); heap_free(host_properties); return NULL; }
VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice phys_dev, const VkDeviceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkDevice *device) { VkDeviceCreateInfo create_info_host; uint32_t max_queue_families; struct VkDevice_T *object; VkResult res; unsigned int i; TRACE("%p %p %p %p\n", phys_dev, create_info, allocator, device); if (allocator) FIXME("Support for allocation callbacks not implemented yet\n"); object = heap_alloc_zero(sizeof(*object)); if (!object) return VK_ERROR_OUT_OF_HOST_MEMORY; object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE; wine_vk_device_convert_create_info(create_info, &create_info_host); res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev, &create_info_host, NULL /* allocator */, &object->device); if (res != VK_SUCCESS) { ERR("Failed to create device.\n"); wine_vk_device_free(object); return res; } /* Just load all function pointers we are aware off. The loader takes care of filtering. * We use vkGetDeviceProcAddr as opposed to vkGetInstanceProcAddr for efficiency reasons * as functions pass through fewer dispatch tables within the loader. */ #define USE_VK_FUNC(name) \ object->funcs.p_##name = (void *)vk_funcs->p_vkGetDeviceProcAddr(object->device, #name); \ if (object->funcs.p_##name == NULL) \ TRACE("Not found %s\n", #name); ALL_VK_DEVICE_FUNCS() #undef USE_VK_FUNC /* We need to cache all queues within the device as each requires wrapping since queues are * dispatchable objects. */ phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(phys_dev->phys_dev, &max_queue_families, NULL); object->max_queue_families = max_queue_families; TRACE("Max queue families: %u\n", object->max_queue_families); object->queues = heap_calloc(max_queue_families, sizeof(*object->queues)); if (!object->queues) { wine_vk_device_free(object); return VK_ERROR_OUT_OF_HOST_MEMORY; } for (i = 0; i < create_info_host.queueCreateInfoCount; i++) { uint32_t family_index = create_info_host.pQueueCreateInfos[i].queueFamilyIndex; uint32_t queue_count = create_info_host.pQueueCreateInfos[i].queueCount; TRACE("queueFamilyIndex %u, queueCount %u\n", family_index, queue_count); object->queues[family_index] = wine_vk_device_alloc_queues(object, family_index, queue_count); if (!object->queues[family_index]) { ERR("Failed to allocate memory for queues\n"); wine_vk_device_free(object); return VK_ERROR_OUT_OF_HOST_MEMORY; } } object->quirks = phys_dev->instance->quirks; *device = object; return VK_SUCCESS; }