1 /*
2 * Copyright 2020 Google LLC
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "vkr_instance.h"
7
8 #include "venus-protocol/vn_protocol_renderer_info.h"
9 #include "venus-protocol/vn_protocol_renderer_instance.h"
10
11 #include "vkr_context.h"
12 #include "vkr_physical_device.h"
13
14 static void
vkr_dispatch_vkEnumerateInstanceVersion(UNUSED struct vn_dispatch_context * dispatch,struct vn_command_vkEnumerateInstanceVersion * args)15 vkr_dispatch_vkEnumerateInstanceVersion(UNUSED struct vn_dispatch_context *dispatch,
16 struct vn_command_vkEnumerateInstanceVersion *args)
17 {
18 vn_replace_vkEnumerateInstanceVersion_args_handle(args);
19 args->ret = vkEnumerateInstanceVersion(args->pApiVersion);
20 }
21
22 static void
vkr_dispatch_vkEnumerateInstanceExtensionProperties(UNUSED struct vn_dispatch_context * dispatch,struct vn_command_vkEnumerateInstanceExtensionProperties * args)23 vkr_dispatch_vkEnumerateInstanceExtensionProperties(
24 UNUSED struct vn_dispatch_context *dispatch,
25 struct vn_command_vkEnumerateInstanceExtensionProperties *args)
26 {
27 VkExtensionProperties private_extensions[] = {
28 {
29 .extensionName = "VK_EXT_command_serialization",
30 },
31 {
32 .extensionName = "VK_MESA_venus_protocol",
33 },
34 };
35
36 if (!args->pProperties) {
37 *args->pPropertyCount = ARRAY_SIZE(private_extensions);
38 args->ret = VK_SUCCESS;
39 return;
40 }
41
42 for (uint32_t i = 0; i < ARRAY_SIZE(private_extensions); i++) {
43 VkExtensionProperties *props = &private_extensions[i];
44 props->specVersion = vn_info_extension_spec_version(props->extensionName);
45 }
46
47 const uint32_t count = MIN2(*args->pPropertyCount, ARRAY_SIZE(private_extensions));
48 memcpy(args->pProperties, private_extensions, sizeof(*args->pProperties) * count);
49 *args->pPropertyCount = count;
50 args->ret = count == ARRAY_SIZE(private_extensions) ? VK_SUCCESS : VK_INCOMPLETE;
51 }
52
53 static VkBool32
vkr_validation_callback(UNUSED VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,UNUSED VkDebugUtilsMessageTypeFlagsEXT messageTypes,const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData,void * pUserData)54 vkr_validation_callback(UNUSED VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
55 UNUSED VkDebugUtilsMessageTypeFlagsEXT messageTypes,
56 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
57 void *pUserData)
58 {
59 struct vkr_context *ctx = pUserData;
60
61 vkr_log(pCallbackData->pMessage);
62
63 if (!ctx->validate_fatal)
64 return false;
65
66 vkr_cs_decoder_set_fatal(&ctx->decoder);
67
68 /* The spec says we "should" return false, because the meaning of true is
69 * layer-defined and is reserved for layer development. And we know that,
70 * for VK_LAYER_KHRONOS_validation, the return value indicates whether the
71 * call should be skipped. Let's do it for now and seek advices.
72 */
73 return true;
74 }
75
76 static void
vkr_dispatch_vkCreateInstance(struct vn_dispatch_context * dispatch,struct vn_command_vkCreateInstance * args)77 vkr_dispatch_vkCreateInstance(struct vn_dispatch_context *dispatch,
78 struct vn_command_vkCreateInstance *args)
79 {
80 struct vkr_context *ctx = dispatch->data;
81
82 if (ctx->instance) {
83 vkr_cs_decoder_set_fatal(&ctx->decoder);
84 return;
85 }
86
87 if (args->pCreateInfo->enabledLayerCount) {
88 args->ret = VK_ERROR_LAYER_NOT_PRESENT;
89 return;
90 }
91
92 if (args->pCreateInfo->enabledExtensionCount) {
93 args->ret = VK_ERROR_EXTENSION_NOT_PRESENT;
94 return;
95 }
96
97 uint32_t instance_version;
98 args->ret = vkEnumerateInstanceVersion(&instance_version);
99 if (args->ret != VK_SUCCESS)
100 return;
101
102 /* require Vulkan 1.1 */
103 if (instance_version < VK_API_VERSION_1_1) {
104 args->ret = VK_ERROR_INITIALIZATION_FAILED;
105 return;
106 }
107
108 VkInstanceCreateInfo *create_info = (VkInstanceCreateInfo *)args->pCreateInfo;
109 const char *layer_names[8];
110 const char *ext_names[8];
111 uint32_t layer_count = 0;
112 uint32_t ext_count = 0;
113
114 /* TODO enable more validation features */
115 const VkValidationFeatureDisableEXT validation_feature_disables_on[] = {
116 VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT,
117 VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT,
118 VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT,
119 VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT,
120 VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT,
121 };
122 /* we are single-threaded */
123 const VkValidationFeatureDisableEXT validation_feature_disables_full[] = {
124 VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT,
125 };
126 VkValidationFeaturesEXT validation_features;
127 VkDebugUtilsMessengerCreateInfoEXT messenger_create_info;
128 if (ctx->validate_level != VKR_CONTEXT_VALIDATE_NONE) {
129 /* let vkCreateInstance return VK_ERROR_LAYER_NOT_PRESENT or
130 * VK_ERROR_EXTENSION_NOT_PRESENT when the layer or extensions are
131 * missing
132 */
133 layer_names[layer_count++] = "VK_LAYER_KHRONOS_validation";
134 ext_names[ext_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
135 ext_names[ext_count++] = VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME;
136
137 validation_features = (const VkValidationFeaturesEXT){
138 .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
139 .pNext = create_info->pNext,
140 };
141 if (ctx->validate_level == VKR_CONTEXT_VALIDATE_ON) {
142 validation_features.disabledValidationFeatureCount =
143 ARRAY_SIZE(validation_feature_disables_on);
144 validation_features.pDisabledValidationFeatures = validation_feature_disables_on;
145 } else {
146 validation_features.disabledValidationFeatureCount =
147 ARRAY_SIZE(validation_feature_disables_full);
148 validation_features.pDisabledValidationFeatures =
149 validation_feature_disables_full;
150 }
151 messenger_create_info = (VkDebugUtilsMessengerCreateInfoEXT){
152 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
153 .pNext = &validation_features,
154 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
155 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
156 .pfnUserCallback = vkr_validation_callback,
157 .pUserData = ctx,
158 };
159
160 create_info->pNext = &messenger_create_info;
161 }
162
163 assert(layer_count <= ARRAY_SIZE(layer_names));
164 create_info->enabledLayerCount = layer_count;
165 create_info->ppEnabledLayerNames = layer_names;
166
167 assert(ext_count <= ARRAY_SIZE(ext_names));
168 create_info->enabledExtensionCount = ext_count;
169 create_info->ppEnabledExtensionNames = ext_names;
170
171 /* patch apiVersion */
172 VkApplicationInfo app_info = {
173 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
174 .apiVersion = VK_API_VERSION_1_1,
175 };
176 if (create_info->pApplicationInfo) {
177 app_info = *create_info->pApplicationInfo;
178 if (app_info.apiVersion < VK_API_VERSION_1_1)
179 app_info.apiVersion = VK_API_VERSION_1_1;
180 }
181 create_info->pApplicationInfo = &app_info;
182
183 struct vkr_instance *instance = vkr_context_alloc_object(
184 ctx, sizeof(*instance), VK_OBJECT_TYPE_INSTANCE, args->pInstance);
185 if (!instance) {
186 args->ret = VK_ERROR_OUT_OF_HOST_MEMORY;
187 return;
188 }
189
190 instance->api_version = app_info.apiVersion;
191
192 vn_replace_vkCreateInstance_args_handle(args);
193 args->ret = vkCreateInstance(create_info, NULL, &instance->base.handle.instance);
194 if (args->ret != VK_SUCCESS) {
195 free(instance);
196 return;
197 }
198
199 instance->get_memory_fd = (PFN_vkGetMemoryFdKHR)vkGetInstanceProcAddr(
200 instance->base.handle.instance, "vkGetMemoryFdKHR");
201 instance->get_fence_fd = (PFN_vkGetFenceFdKHR)vkGetInstanceProcAddr(
202 instance->base.handle.instance, "vkGetFenceFdKHR");
203
204 if (ctx->validate_level != VKR_CONTEXT_VALIDATE_NONE) {
205 instance->create_debug_utils_messenger =
206 (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
207 instance->base.handle.instance, "vkCreateDebugUtilsMessengerEXT");
208 instance->destroy_debug_utils_messenger =
209 (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
210 instance->base.handle.instance, "vkDestroyDebugUtilsMessengerEXT");
211
212 messenger_create_info.pNext = NULL;
213 args->ret = instance->create_debug_utils_messenger(instance->base.handle.instance,
214 &messenger_create_info, NULL,
215 &instance->validation_messenger);
216 if (args->ret != VK_SUCCESS) {
217 vkDestroyInstance(instance->base.handle.instance, NULL);
218 free(instance);
219 return;
220 }
221 }
222
223 vkr_context_add_instance(ctx, instance, app_info.pApplicationName);
224 }
225
226 void
vkr_instance_destroy(struct vkr_context * ctx,struct vkr_instance * instance)227 vkr_instance_destroy(struct vkr_context *ctx, struct vkr_instance *instance)
228 {
229 for (uint32_t i = 0; i < instance->physical_device_count; i++) {
230 struct vkr_physical_device *physical_dev = instance->physical_devices[i];
231 if (!physical_dev)
232 break;
233
234 vkr_physical_device_destroy(ctx, physical_dev);
235 }
236
237 if (ctx->validate_level != VKR_CONTEXT_VALIDATE_NONE) {
238 instance->destroy_debug_utils_messenger(instance->base.handle.instance,
239 instance->validation_messenger, NULL);
240 }
241
242 vkDestroyInstance(instance->base.handle.instance, NULL);
243
244 free(instance->physical_device_handles);
245 free(instance->physical_devices);
246
247 vkr_context_remove_instance(ctx, instance);
248 }
249
250 static void
vkr_dispatch_vkDestroyInstance(struct vn_dispatch_context * dispatch,struct vn_command_vkDestroyInstance * args)251 vkr_dispatch_vkDestroyInstance(struct vn_dispatch_context *dispatch,
252 struct vn_command_vkDestroyInstance *args)
253 {
254 struct vkr_context *ctx = dispatch->data;
255 struct vkr_instance *instance = vkr_instance_from_handle(args->instance);
256
257 if (ctx->instance != instance) {
258 vkr_cs_decoder_set_fatal(&ctx->decoder);
259 return;
260 }
261
262 vkr_instance_destroy(ctx, instance);
263 }
264
265 void
vkr_context_init_instance_dispatch(struct vkr_context * ctx)266 vkr_context_init_instance_dispatch(struct vkr_context *ctx)
267 {
268 struct vn_dispatch_context *dispatch = &ctx->dispatch;
269
270 dispatch->dispatch_vkEnumerateInstanceVersion =
271 vkr_dispatch_vkEnumerateInstanceVersion;
272 dispatch->dispatch_vkEnumerateInstanceExtensionProperties =
273 vkr_dispatch_vkEnumerateInstanceExtensionProperties;
274 /* we don't advertise layers (and should never) */
275 dispatch->dispatch_vkEnumerateInstanceLayerProperties = NULL;
276 dispatch->dispatch_vkCreateInstance = vkr_dispatch_vkCreateInstance;
277 dispatch->dispatch_vkDestroyInstance = vkr_dispatch_vkDestroyInstance;
278 dispatch->dispatch_vkGetInstanceProcAddr = NULL;
279 }
280