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_instance.h"
9
10 #include "vkr_context.h"
11 #include "vkr_physical_device.h"
12
13 static void
vkr_dispatch_vkEnumerateInstanceVersion(UNUSED struct vn_dispatch_context * dispatch,struct vn_command_vkEnumerateInstanceVersion * args)14 vkr_dispatch_vkEnumerateInstanceVersion(UNUSED struct vn_dispatch_context *dispatch,
15 struct vn_command_vkEnumerateInstanceVersion *args)
16 {
17 vn_replace_vkEnumerateInstanceVersion_args_handle(args);
18
19 uint32_t version = 0;
20 args->ret = vkEnumerateInstanceVersion(&version);
21 if (args->ret == VK_SUCCESS)
22 version = vkr_api_version_cap_minor(version, VKR_MAX_API_VERSION);
23
24 *args->pApiVersion = version;
25 }
26
27 static void
vkr_dispatch_vkEnumerateInstanceExtensionProperties(UNUSED struct vn_dispatch_context * dispatch,struct vn_command_vkEnumerateInstanceExtensionProperties * args)28 vkr_dispatch_vkEnumerateInstanceExtensionProperties(
29 UNUSED struct vn_dispatch_context *dispatch,
30 struct vn_command_vkEnumerateInstanceExtensionProperties *args)
31 {
32 VkExtensionProperties private_extensions[] = {
33 {
34 .extensionName = "VK_EXT_command_serialization",
35 },
36 {
37 .extensionName = "VK_MESA_venus_protocol",
38 },
39 };
40
41 if (!args->pProperties) {
42 *args->pPropertyCount = ARRAY_SIZE(private_extensions);
43 args->ret = VK_SUCCESS;
44 return;
45 }
46
47 for (uint32_t i = 0; i < ARRAY_SIZE(private_extensions); i++) {
48 VkExtensionProperties *props = &private_extensions[i];
49 props->specVersion = vkr_extension_get_spec_version(props->extensionName);
50 }
51
52 const uint32_t count = MIN2(*args->pPropertyCount, ARRAY_SIZE(private_extensions));
53 memcpy(args->pProperties, private_extensions, sizeof(*args->pProperties) * count);
54 *args->pPropertyCount = count;
55 args->ret = count == ARRAY_SIZE(private_extensions) ? VK_SUCCESS : VK_INCOMPLETE;
56 }
57
58 static VkBool32
vkr_validation_callback(UNUSED VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,UNUSED VkDebugUtilsMessageTypeFlagsEXT messageTypes,const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData,void * pUserData)59 vkr_validation_callback(UNUSED VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
60 UNUSED VkDebugUtilsMessageTypeFlagsEXT messageTypes,
61 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
62 void *pUserData)
63 {
64 struct vkr_context *ctx = pUserData;
65
66 vkr_log(pCallbackData->pMessage);
67
68 if (!ctx->validate_fatal)
69 return false;
70
71 vkr_cs_decoder_set_fatal(&ctx->decoder);
72
73 /* The spec says we "should" return false, because the meaning of true is
74 * layer-defined and is reserved for layer development. And we know that,
75 * for VK_LAYER_KHRONOS_validation, the return value indicates whether the
76 * call should be skipped. Let's do it for now and seek advices.
77 */
78 return true;
79 }
80
81 static void
vkr_dispatch_vkCreateInstance(struct vn_dispatch_context * dispatch,struct vn_command_vkCreateInstance * args)82 vkr_dispatch_vkCreateInstance(struct vn_dispatch_context *dispatch,
83 struct vn_command_vkCreateInstance *args)
84 {
85 struct vkr_context *ctx = dispatch->data;
86
87 if (ctx->instance) {
88 vkr_cs_decoder_set_fatal(&ctx->decoder);
89 return;
90 }
91
92 if (args->pCreateInfo->enabledLayerCount) {
93 args->ret = VK_ERROR_LAYER_NOT_PRESENT;
94 return;
95 }
96
97 if (args->pCreateInfo->enabledExtensionCount) {
98 args->ret = VK_ERROR_EXTENSION_NOT_PRESENT;
99 return;
100 }
101
102 uint32_t instance_version;
103 args->ret = vkEnumerateInstanceVersion(&instance_version);
104 if (args->ret != VK_SUCCESS)
105 return;
106
107 /* require Vulkan 1.1 */
108 if (instance_version < VK_API_VERSION_1_1) {
109 args->ret = VK_ERROR_INITIALIZATION_FAILED;
110 return;
111 }
112
113 VkInstanceCreateInfo *create_info = (VkInstanceCreateInfo *)args->pCreateInfo;
114 const char *layer_names[8];
115 const char *ext_names[8];
116 uint32_t layer_count = 0;
117 uint32_t ext_count = 0;
118
119 /* TODO enable more validation features */
120 const VkValidationFeatureDisableEXT validation_feature_disables_on[] = {
121 VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT,
122 VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT,
123 VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT,
124 VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT,
125 VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT,
126 };
127 /* we are single-threaded */
128 const VkValidationFeatureDisableEXT validation_feature_disables_full[] = {
129 VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT,
130 };
131 VkValidationFeaturesEXT validation_features;
132 VkDebugUtilsMessengerCreateInfoEXT messenger_create_info;
133 if (ctx->validate_level != VKR_CONTEXT_VALIDATE_NONE) {
134 /* let vkCreateInstance return VK_ERROR_LAYER_NOT_PRESENT or
135 * VK_ERROR_EXTENSION_NOT_PRESENT when the layer or extensions are
136 * missing
137 */
138 layer_names[layer_count++] = "VK_LAYER_KHRONOS_validation";
139 ext_names[ext_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
140 ext_names[ext_count++] = VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME;
141
142 validation_features = (const VkValidationFeaturesEXT){
143 .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
144 .pNext = create_info->pNext,
145 };
146 if (ctx->validate_level == VKR_CONTEXT_VALIDATE_ON) {
147 validation_features.disabledValidationFeatureCount =
148 ARRAY_SIZE(validation_feature_disables_on);
149 validation_features.pDisabledValidationFeatures = validation_feature_disables_on;
150 } else {
151 validation_features.disabledValidationFeatureCount =
152 ARRAY_SIZE(validation_feature_disables_full);
153 validation_features.pDisabledValidationFeatures =
154 validation_feature_disables_full;
155 }
156 messenger_create_info = (VkDebugUtilsMessengerCreateInfoEXT){
157 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
158 .pNext = &validation_features,
159 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
160 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
161 .pfnUserCallback = vkr_validation_callback,
162 .pUserData = ctx,
163 };
164
165 create_info->pNext = &messenger_create_info;
166 }
167
168 assert(layer_count <= ARRAY_SIZE(layer_names));
169 create_info->enabledLayerCount = layer_count;
170 create_info->ppEnabledLayerNames = layer_names;
171
172 assert(ext_count <= ARRAY_SIZE(ext_names));
173 create_info->enabledExtensionCount = ext_count;
174 create_info->ppEnabledExtensionNames = ext_names;
175
176 /* patch apiVersion */
177 VkApplicationInfo app_info = {
178 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
179 .apiVersion = VK_API_VERSION_1_1,
180 };
181 if (create_info->pApplicationInfo) {
182 app_info = *create_info->pApplicationInfo;
183 if (app_info.apiVersion < VK_API_VERSION_1_1)
184 app_info.apiVersion = VK_API_VERSION_1_1;
185 }
186 create_info->pApplicationInfo = &app_info;
187
188 struct vkr_instance *instance = vkr_context_alloc_object(
189 ctx, sizeof(*instance), VK_OBJECT_TYPE_INSTANCE, args->pInstance);
190 if (!instance) {
191 args->ret = VK_ERROR_OUT_OF_HOST_MEMORY;
192 return;
193 }
194
195 instance->api_version = app_info.apiVersion;
196
197 vn_replace_vkCreateInstance_args_handle(args);
198 args->ret = vkCreateInstance(create_info, NULL, &instance->base.handle.instance);
199 if (args->ret != VK_SUCCESS) {
200 free(instance);
201 return;
202 }
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