a9da9d96eb19eaefc2c308fda156d6bb4cc9a72b
[mesa.git] / src / libre-soc / vulkan / libresoc_device.c
1 /*
2 * Copyright © 2019 Raspberry Pi
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <sys/mman.h>
28 #include <sys/sysinfo.h>
29 #include <unistd.h>
30
31 #include "util/debug.h"
32 #include "libresoc_private.h"
33 #include "vk_util.h"
34 #include "vk_alloc.h"
35
36 VkResult
37 libresoc_EnumerateInstanceExtensionProperties(const char *pLayerName,
38 uint32_t *pPropertyCount,
39 VkExtensionProperties *pProperties)
40 {
41 if (getenv("LIBRESOC_TRACE")) {
42 fprintf(stderr, "EnumerateInstanceExtensionProperties called for: %s \n", pLayerName);
43 }
44 VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
45
46 for (int i = 0; i < LIBRESOC_INSTANCE_EXTENSION_COUNT; i++) {
47 if (libresoc_instance_extensions_supported.extensions[i]) {
48 vk_outarray_append(&out, prop) {
49 *prop = libresoc_instance_extensions[i];
50 }
51 }
52 }
53
54 return vk_outarray_status(&out);
55 }
56
57 static void *
58 default_alloc_func(void *pUserData, size_t size, size_t align,
59 VkSystemAllocationScope allocationScope)
60 {
61 return malloc(size);
62 }
63
64 static void *
65 default_realloc_func(void *pUserData, void *pOriginal, size_t size,
66 size_t align, VkSystemAllocationScope allocationScope)
67 {
68 return realloc(pOriginal, size);
69 }
70
71 static void
72 default_free_func(void *pUserData, void *pMemory)
73 {
74 free(pMemory);
75 }
76
77 static const VkAllocationCallbacks default_alloc = {
78 .pUserData = NULL,
79 .pfnAllocation = default_alloc_func,
80 .pfnReallocation = default_realloc_func,
81 .pfnFree = default_free_func,
82 };
83
84 static const struct debug_control libresoc_debug_options[] = {
85 {"nofastclears", LIBRESOC_DEBUG_NO_FAST_CLEARS},
86 {"nodcc", LIBRESOC_DEBUG_NO_DCC},
87 {"shaders", LIBRESOC_DEBUG_DUMP_SHADERS},
88 {"nocache", LIBRESOC_DEBUG_NO_CACHE},
89 {"shaderstats", LIBRESOC_DEBUG_DUMP_SHADER_STATS},
90 {"nohiz", LIBRESOC_DEBUG_NO_HIZ},
91 {"nocompute", LIBRESOC_DEBUG_NO_COMPUTE_QUEUE},
92 {"allbos", LIBRESOC_DEBUG_ALL_BOS},
93 {"noibs", LIBRESOC_DEBUG_NO_IBS},
94 {"spirv", LIBRESOC_DEBUG_DUMP_SPIRV},
95 {"vmfaults", LIBRESOC_DEBUG_VM_FAULTS},
96 {"zerovram", LIBRESOC_DEBUG_ZERO_VRAM},
97 {"syncshaders", LIBRESOC_DEBUG_SYNC_SHADERS},
98 {"preoptir", LIBRESOC_DEBUG_PREOPTIR},
99 {"nodynamicbounds", LIBRESOC_DEBUG_NO_DYNAMIC_BOUNDS},
100 {"nooutoforder", LIBRESOC_DEBUG_NO_OUT_OF_ORDER},
101 {"info", LIBRESOC_DEBUG_INFO},
102 {"errors", LIBRESOC_DEBUG_ERRORS},
103 {"startup", LIBRESOC_DEBUG_STARTUP},
104 {"checkir", LIBRESOC_DEBUG_CHECKIR},
105 {"nothreadllvm", LIBRESOC_DEBUG_NOTHREADLLVM},
106 {"nobinning", LIBRESOC_DEBUG_NOBINNING},
107 {"nongg", LIBRESOC_DEBUG_NO_NGG},
108 {"allentrypoints", LIBRESOC_DEBUG_ALL_ENTRYPOINTS},
109 {"metashaders", LIBRESOC_DEBUG_DUMP_META_SHADERS},
110 {"nomemorycache", LIBRESOC_DEBUG_NO_MEMORY_CACHE},
111 {"llvm", LIBRESOC_DEBUG_LLVM},
112 {"forcecompress", LIBRESOC_DEBUG_FORCE_COMPRESS},
113 {NULL, 0}
114 };
115
116 const char *
117 libresoc_get_debug_option_name(int id)
118 {
119 assert(id < ARRAY_SIZE(libresoc_debug_options) - 1);
120 return libresoc_debug_options[id].string;
121 }
122 VkResult
123 libresoc_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
124 const VkAllocationCallbacks *pAllocator,
125 VkInstance *pInstance)
126 {
127 if (getenv("LIBRESOC_TRACE")) {
128 fprintf(stderr, "CreateInstance called. \n");
129 }
130 struct libresoc_instance *instance;
131
132 instance = vk_zalloc2(&default_alloc, pAllocator, sizeof(*instance), 8,
133 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
134 if (!instance)
135 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
136
137 vk_object_base_init(NULL, &instance->base, VK_OBJECT_TYPE_INSTANCE);
138
139 if (pAllocator)
140 instance->alloc = *pAllocator;
141 else
142 instance->alloc = default_alloc;
143 if (pCreateInfo->pApplicationInfo) {
144 const VkApplicationInfo *app = pCreateInfo->pApplicationInfo;
145
146 instance->engineName =
147 vk_strdup(&instance->alloc, app->pEngineName,
148 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
149 instance->engineVersion = app->engineVersion;
150 instance->apiVersion = app->apiVersion;
151 }
152 instance->debug_flags = parse_debug_string(getenv("LIBRESOC_DEBUG"),
153 libresoc_debug_options);
154 /*TODO : enable extensions*/
155 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
156 int idx;
157 for (idx = 0; idx < LIBRESOC_INSTANCE_EXTENSION_COUNT; idx++) {
158 if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i],
159 libresoc_instance_extensions[idx].extensionName))
160 break;
161 }
162
163 if (idx >= LIBRESOC_INSTANCE_EXTENSION_COUNT ||
164 !libresoc_instance_extensions_supported.extensions[idx]) {
165 vk_object_base_finish(&instance->base);
166 vk_free2(&default_alloc, pAllocator, instance);
167 return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT);
168 }
169
170 instance->enabled_extensions.extensions[idx] = true;
171 }
172 for (unsigned i = 0; i < ARRAY_SIZE(instance->dispatch.entrypoints); i++) {
173 /* Vulkan requires that entrypoints for extensions which have
174 * not been enabled must not be advertised.
175 */
176 if (!libresoc_instance_entrypoint_is_enabled(i, instance->apiVersion,
177 &instance->enabled_extensions)) {
178 instance->dispatch.entrypoints[i] = NULL;
179 } else {
180 instance->dispatch.entrypoints[i] =
181 libresoc_instance_dispatch_table.entrypoints[i];
182 }
183 }
184 for (unsigned i = 0; i < ARRAY_SIZE(instance->physical_device_dispatch.entrypoints); i++) {
185 /* Vulkan requires that entrypoints for extensions which have
186 * not been enabled must not be advertised.
187 */
188 if (!libresoc_physical_device_entrypoint_is_enabled(i, instance->apiVersion,
189 &instance->enabled_extensions)) {
190 instance->physical_device_dispatch.entrypoints[i] = NULL;
191 } else {
192 instance->physical_device_dispatch.entrypoints[i] =
193 libresoc_physical_device_dispatch_table.entrypoints[i];
194 }
195 }
196
197 for (unsigned i = 0; i < ARRAY_SIZE(instance->device_dispatch.entrypoints); i++) {
198 /* Vulkan requires that entrypoints for extensions which have
199 * not been enabled must not be advertised.
200 */
201 if (!libresoc_device_entrypoint_is_enabled(i, instance->apiVersion,
202 &instance->enabled_extensions, NULL)) {
203 instance->device_dispatch.entrypoints[i] = NULL;
204 } else {
205 instance->device_dispatch.entrypoints[i] =
206 libresoc_device_dispatch_table.entrypoints[i];
207 }
208 }
209 instance->physical_devices_enumerated = false;
210 list_inithead(&instance->physical_devices);
211 *pInstance = libresoc_instance_to_handle(instance);
212
213 return VK_SUCCESS;
214 }
215
216 void
217 libresoc_DestroyInstance(VkInstance _instance,
218 const VkAllocationCallbacks *pAllocator)
219 {
220 if (getenv("LIBRESOC_TRACE")) {
221 fprintf(stderr, "DestroyInstance called. \n");
222 }
223 /* FIXME: stub */
224 }
225
226 static VkResult
227 libresoc_physical_device_try_create(struct libresoc_instance *instance,
228 struct libresoc_physical_device **device_out)
229 {
230 VkResult result;
231
232 struct libresoc_physical_device *device =
233 vk_zalloc2(&instance->alloc, NULL, sizeof(*device), 8,
234 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
235 if (!device) {
236 result = vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
237 return result;
238 }
239
240 device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
241 device->instance = instance;
242
243 snprintf(device->name, sizeof(device->name),
244 "LIBRE-SOC DEVICE");
245 *device_out = device;
246
247 return VK_SUCCESS;
248
249 }
250 static VkResult
251 libresoc_enumerate_physical_devices(struct libresoc_instance *instance)
252 {
253
254 if (instance->physical_devices_enumerated)
255 return VK_SUCCESS;
256
257 instance->physical_devices_enumerated = true;
258 VkResult result = VK_SUCCESS;
259 /* the driver creates a null
260 * device that allows to test the compiler without having a physical device
261 */
262 struct libresoc_physical_device *pdevice;
263
264 result = libresoc_physical_device_try_create(instance, &pdevice);
265 if (result != VK_SUCCESS)
266 return result;
267
268 list_addtail(&pdevice->link, &instance->physical_devices);
269 return VK_SUCCESS;
270
271 }
272
273 VkResult
274 libresoc_EnumeratePhysicalDevices(VkInstance _instance,
275 uint32_t *pPhysicalDeviceCount,
276 VkPhysicalDevice *pPhysicalDevices)
277 {
278 if (getenv("LIBRESOC_TRACE")) {
279 fprintf(stderr, "EnumeratePhysicalDevices called\n");
280 }
281 LIBRESOC_FROM_HANDLE(libresoc_instance, instance, _instance);
282 VK_OUTARRAY_MAKE(out, pPhysicalDevices, pPhysicalDeviceCount);
283
284 VkResult result = libresoc_enumerate_physical_devices(instance);
285 if (result != VK_SUCCESS)
286 return result;
287
288 list_for_each_entry(struct libresoc_physical_device, pdevice,
289 &instance->physical_devices, link) {
290 vk_outarray_append(&out, i) {
291 *i = libresoc_physical_device_to_handle(pdevice);
292 }
293 }
294
295 return vk_outarray_status(&out);
296 }
297
298 void
299 libresoc_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
300 VkPhysicalDeviceFeatures *pFeatures)
301 {
302 if (getenv("LIBRESOC_TRACE")) {
303 fprintf(stderr, "GetPhysicalDeviceFeatures called. \n");
304 }
305 //LIBRESOC_FROM_HANDLE(libresoc_physical_device, pdevice, physicalDevice);
306 memset(pFeatures, 0, sizeof(*pFeatures));
307
308 *pFeatures = (VkPhysicalDeviceFeatures) {
309 .robustBufferAccess = true,
310 .fullDrawIndexUint32 = true,
311 .imageCubeArray = true,
312 .independentBlend = true,
313 .geometryShader = true,
314 .tessellationShader = true,
315 .sampleRateShading = true,
316 .dualSrcBlend = true,
317 .logicOp = true,
318 .multiDrawIndirect = true,
319 .drawIndirectFirstInstance = true,
320 .depthClamp = true,
321 .depthBiasClamp = true,
322 .fillModeNonSolid = true,
323 .depthBounds = true,
324 .wideLines = true,
325 .largePoints = true,
326 .alphaToOne = true,
327 .multiViewport = true,
328 .samplerAnisotropy = true,
329 .textureCompressionETC2 = false,
330 .textureCompressionASTC_LDR = false,
331 .textureCompressionBC = true,
332 .occlusionQueryPrecise = true,
333 .pipelineStatisticsQuery = true,
334 .vertexPipelineStoresAndAtomics = true,
335 .fragmentStoresAndAtomics = true,
336 .shaderTessellationAndGeometryPointSize = true,
337 .shaderImageGatherExtended = true,
338 .shaderStorageImageExtendedFormats = true,
339 .shaderStorageImageMultisample = true,
340 .shaderUniformBufferArrayDynamicIndexing = true,
341 .shaderSampledImageArrayDynamicIndexing = true,
342 .shaderStorageBufferArrayDynamicIndexing = true,
343 .shaderStorageImageArrayDynamicIndexing = true,
344 .shaderStorageImageReadWithoutFormat = true,
345 .shaderStorageImageWriteWithoutFormat = true,
346 .shaderClipDistance = true,
347 .shaderCullDistance = true,
348 .shaderFloat64 = true,
349 .shaderInt64 = true,
350 .shaderInt16 = true,
351 .sparseBinding = true,
352 .variableMultisampleRate = true,
353 .shaderResourceMinLod = true,
354 .inheritedQueries = true,
355 };
356 }
357
358 static size_t
359 libresoc_max_descriptor_set_size()
360 {
361 /* make sure that the entire descriptor set is addressable with a signed
362 * 32-bit int. So the sum of all limits scaled by descriptor size has to
363 * be at most 2 GiB. the combined image & samples object count as one of
364 * both. This limit is for the pipeline layout, not for the set layout, but
365 * there is no set limit, so we just set a pipeline limit. I don't think
366 * any app is going to hit this soon. */
367 return ((1ull << 31) - 16 * MAX_DYNAMIC_BUFFERS
368 - MAX_INLINE_UNIFORM_BLOCK_SIZE * MAX_INLINE_UNIFORM_BLOCK_COUNT) /
369 (32 /* uniform buffer, 32 due to potential space wasted on alignment */ +
370 32 /* storage buffer, 32 due to potential space wasted on alignment */ +
371 32 /* sampler, largest when combined with image */ +
372 64 /* sampled image */ +
373 64 /* storage image */);
374 }
375
376 void
377 libresoc_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
378 VkPhysicalDeviceProperties *pProperties)
379 {
380 if (getenv("LIBRESOC_TRACE")) {
381 fprintf(stderr, "GetPhysicalDeviceProperties called. \n");
382 }
383 LIBRESOC_FROM_HANDLE(libresoc_physical_device, pdevice, physicalDevice);
384 VkSampleCountFlags sample_counts = 0xf;
385
386 size_t max_descriptor_set_size = libresoc_max_descriptor_set_size();
387
388 VkPhysicalDeviceLimits limits = {
389 .maxImageDimension1D = (1 << 14),
390 .maxImageDimension2D = (1 << 14),
391 .maxImageDimension3D = (1 << 11),
392 .maxImageDimensionCube = (1 << 14),
393 .maxImageArrayLayers = (1 << 11),
394 .maxTexelBufferElements = UINT32_MAX,
395 .maxUniformBufferRange = UINT32_MAX,
396 .maxStorageBufferRange = UINT32_MAX,
397 .maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE,
398 .maxMemoryAllocationCount = UINT32_MAX,
399 .maxSamplerAllocationCount = 64 * 1024,
400 .bufferImageGranularity = 64, /* A cache line */
401 .sparseAddressSpaceSize = LIBRESOC_MAX_MEMORY_ALLOCATION_SIZE, /* buffer max size */
402 .maxBoundDescriptorSets = MAX_SETS,
403 .maxPerStageDescriptorSamplers = max_descriptor_set_size,
404 .maxPerStageDescriptorUniformBuffers = max_descriptor_set_size,
405 .maxPerStageDescriptorStorageBuffers = max_descriptor_set_size,
406 .maxPerStageDescriptorSampledImages = max_descriptor_set_size,
407 .maxPerStageDescriptorStorageImages = max_descriptor_set_size,
408 .maxPerStageDescriptorInputAttachments = max_descriptor_set_size,
409 .maxPerStageResources = max_descriptor_set_size,
410 .maxDescriptorSetSamplers = max_descriptor_set_size,
411 .maxDescriptorSetUniformBuffers = max_descriptor_set_size,
412 .maxDescriptorSetUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS,
413 .maxDescriptorSetStorageBuffers = max_descriptor_set_size,
414 .maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS,
415 .maxDescriptorSetSampledImages = max_descriptor_set_size,
416 .maxDescriptorSetStorageImages = max_descriptor_set_size,
417 .maxDescriptorSetInputAttachments = max_descriptor_set_size,
418 .maxVertexInputAttributes = MAX_VERTEX_ATTRIBS,
419 .maxVertexInputBindings = MAX_VBS,
420 .maxVertexInputAttributeOffset = 2047,
421 .maxVertexInputBindingStride = 2048,
422 .maxVertexOutputComponents = 128,
423 .maxTessellationGenerationLevel = 64,
424 .maxTessellationPatchSize = 32,
425 .maxTessellationControlPerVertexInputComponents = 128,
426 .maxTessellationControlPerVertexOutputComponents = 128,
427 .maxTessellationControlPerPatchOutputComponents = 120,
428 .maxTessellationControlTotalOutputComponents = 4096,
429 .maxTessellationEvaluationInputComponents = 128,
430 .maxTessellationEvaluationOutputComponents = 128,
431 .maxGeometryShaderInvocations = 127,
432 .maxGeometryInputComponents = 64,
433 .maxGeometryOutputComponents = 128,
434 .maxGeometryOutputVertices = 256,
435 .maxGeometryTotalOutputComponents = 1024,
436 .maxFragmentInputComponents = 128,
437 .maxFragmentOutputAttachments = 8,
438 .maxFragmentDualSrcAttachments = 1,
439 .maxFragmentCombinedOutputResources = 8,
440 .maxComputeSharedMemorySize = 32768,
441 .maxComputeWorkGroupCount = { 65535, 65535, 65535 },
442 .maxComputeWorkGroupInvocations = 1024,
443 .maxComputeWorkGroupSize = {
444 1024,
445 1024,
446 1024
447 },
448 .subPixelPrecisionBits = 8,
449 .subTexelPrecisionBits = 8,
450 .mipmapPrecisionBits = 8,
451 .maxDrawIndexedIndexValue = UINT32_MAX,
452 .maxDrawIndirectCount = UINT32_MAX,
453 .maxSamplerLodBias = 16,
454 .maxSamplerAnisotropy = 16,
455 .maxViewports = MAX_VIEWPORTS,
456 .maxViewportDimensions = { (1 << 14), (1 << 14) },
457 .viewportBoundsRange = { INT16_MIN, INT16_MAX },
458 .viewportSubPixelBits = 8,
459 .minMemoryMapAlignment = 4096, /* A page */
460 .minTexelBufferOffsetAlignment = 4,
461 .minUniformBufferOffsetAlignment = 4,
462 .minStorageBufferOffsetAlignment = 4,
463 .minTexelOffset = -32,
464 .maxTexelOffset = 31,
465 .minTexelGatherOffset = -32,
466 .maxTexelGatherOffset = 31,
467 .minInterpolationOffset = -2,
468 .maxInterpolationOffset = 2,
469 .subPixelInterpolationOffsetBits = 8,
470 .maxFramebufferWidth = (1 << 14),
471 .maxFramebufferHeight = (1 << 14),
472 .maxFramebufferLayers = (1 << 10),
473 .framebufferColorSampleCounts = sample_counts,
474 .framebufferDepthSampleCounts = sample_counts,
475 .framebufferStencilSampleCounts = sample_counts,
476 .framebufferNoAttachmentsSampleCounts = sample_counts,
477 .maxColorAttachments = MAX_RTS,
478 .sampledImageColorSampleCounts = sample_counts,
479 .sampledImageIntegerSampleCounts = sample_counts,
480 .sampledImageDepthSampleCounts = sample_counts,
481 .sampledImageStencilSampleCounts = sample_counts,
482 .storageImageSampleCounts = sample_counts,
483 .maxSampleMaskWords = 1,
484 .timestampComputeAndGraphics = true,
485 .timestampPeriod = 1000000.0 /* FIXME /pdevice->rad_info.clock_crystal_freq*/,
486 .maxClipDistances = 8,
487 .maxCullDistances = 8,
488 .maxCombinedClipAndCullDistances = 8,
489 .discreteQueuePriorities = 2,
490 .pointSizeRange = { 0.0, 8191.875 },
491 .lineWidthRange = { 0.0, 8191.875 },
492 .pointSizeGranularity = (1.0 / 8.0),
493 .lineWidthGranularity = (1.0 / 8.0),
494 .strictLines = false, /* FINISHME */
495 .standardSampleLocations = true,
496 .optimalBufferCopyOffsetAlignment = 128,
497 .optimalBufferCopyRowPitchAlignment = 128,
498 .nonCoherentAtomSize = 64,
499 };
500
501 *pProperties = (VkPhysicalDeviceProperties) {
502 .apiVersion = libresoc_physical_device_api_version(pdevice),
503 .driverVersion = vk_get_driver_version(),
504 .vendorID = 1, //TODO: some dummy value
505 .deviceID = 1, //TODO: dome dummay value
506 .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
507 .limits = limits,
508 .sparseProperties = {0},
509 };
510
511 strcpy(pProperties->deviceName, pdevice->name);
512 memcpy(pProperties->pipelineCacheUUID, pdevice->cache_uuid, VK_UUID_SIZE);
513 }
514
515 static void libresoc_get_physical_device_queue_family_properties(
516 struct libresoc_physical_device* pdevice,
517 uint32_t* pCount,
518 VkQueueFamilyProperties** pQueueFamilyProperties)
519 {
520 int num_queue_families = 1;
521 int idx;
522
523 if (pQueueFamilyProperties == NULL) {
524 *pCount = num_queue_families;
525 return;
526 }
527
528 if (!*pCount)
529 return;
530
531 idx = 0;
532 if (*pCount >= 1) {
533 *pQueueFamilyProperties[idx] = (VkQueueFamilyProperties) {
534 .queueFlags = VK_QUEUE_GRAPHICS_BIT |
535 VK_QUEUE_COMPUTE_BIT |
536 VK_QUEUE_TRANSFER_BIT |
537 VK_QUEUE_SPARSE_BINDING_BIT,
538 .queueCount = 1,
539 .timestampValidBits = 64,
540 .minImageTransferGranularity = (VkExtent3D) { 1, 1, 1 },
541 };
542 idx++;
543 }
544
545 *pCount = idx;
546 }
547
548 void
549 libresoc_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
550 uint32_t *pCount,
551 VkQueueFamilyProperties *pQueueFamilyProperties)
552 {
553 if (getenv("LIBRESOC_TRACE")) {
554 fprintf(stderr, "GetPhysicalDeviceQueueFamilyProperites called. \n");
555 }
556 LIBRESOC_FROM_HANDLE(libresoc_physical_device, pdevice, physicalDevice);
557 if (!pQueueFamilyProperties) {
558 libresoc_get_physical_device_queue_family_properties(pdevice, pCount, NULL);
559 return;
560 }
561 VkQueueFamilyProperties *properties[] = {
562 pQueueFamilyProperties + 0,
563 pQueueFamilyProperties + 1,
564 pQueueFamilyProperties + 2,
565 };
566 libresoc_get_physical_device_queue_family_properties(pdevice, pCount, properties);
567 assert(*pCount <= 3);
568 }
569
570 void
571 libresoc_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
572 VkPhysicalDeviceMemoryProperties *pMemoryProperties)
573 {
574 if (getenv("LIBRESOC_TRACE")) {
575 fprintf(stderr, "GetPhysicalDEviceMemoryProperties called. \n");
576 }
577 /* FIXME: stub */
578 }
579
580 void
581 libresoc_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties) {
582
583 if (getenv("LIBRESOC_TRACE")) {
584 fprintf(stderr, "GetPhysicalDeviceFormatProperties called. \n");
585 }
586 /* FIXME: stub */
587 }
588
589 VkResult
590 libresoc_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties)
591 {
592 if (getenv("LIBRESOC_TRACE")) {
593 fprintf(stderr, "GetPhysicalDEviceImageFormatProperties called. \n");
594 }
595
596 /* FIXME: stub */
597 return VK_SUCCESS;
598 }
599 void
600 libresoc_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties)
601 {
602 if (getenv("LIBRESOC_TRACE")) {
603 fprintf(stderr, "GetPhysicalDeviceSparseImageFormatProperties called. \n");
604 }
605 /* FIXME: stub */
606 }
607 PFN_vkVoidFunction
608 libresoc_GetInstanceProcAddr(VkInstance _instance,
609 const char *pName)
610 {
611 if (getenv("LIBRESOC_TRACE")) {
612 fprintf(stderr, "GetInstanceProcAddr called for: %s \n", pName);
613 }
614 LIBRESOC_FROM_HANDLE(libresoc_instance, instance, _instance);
615
616 /* The Vulkan 1.0 spec for vkGetInstanceProcAddr has a table of exactly
617 * when we have to return valid function pointers, NULL, or it's left
618 * undefined. See the table for exact details.
619 */
620 if (pName == NULL)
621 return NULL;
622
623 #define LOOKUP_LIBRESOC_ENTRYPOINT(entrypoint) \
624 if (strcmp(pName, "vk" #entrypoint) == 0) \
625 return (PFN_vkVoidFunction)libresoc_##entrypoint
626
627 LOOKUP_LIBRESOC_ENTRYPOINT(EnumerateInstanceExtensionProperties);
628 LOOKUP_LIBRESOC_ENTRYPOINT(CreateInstance);
629 LOOKUP_LIBRESOC_ENTRYPOINT(DestroyInstance);
630 LOOKUP_LIBRESOC_ENTRYPOINT(EnumeratePhysicalDevices);
631 LOOKUP_LIBRESOC_ENTRYPOINT(GetPhysicalDeviceFeatures);
632 LOOKUP_LIBRESOC_ENTRYPOINT(GetPhysicalDeviceFormatProperties);
633 LOOKUP_LIBRESOC_ENTRYPOINT(GetPhysicalDeviceImageFormatProperties);
634 LOOKUP_LIBRESOC_ENTRYPOINT(GetPhysicalDeviceProperties);
635 LOOKUP_LIBRESOC_ENTRYPOINT(GetPhysicalDeviceQueueFamilyProperties);
636 LOOKUP_LIBRESOC_ENTRYPOINT(GetPhysicalDeviceMemoryProperties);
637 LOOKUP_LIBRESOC_ENTRYPOINT(GetDeviceProcAddr);
638 LOOKUP_LIBRESOC_ENTRYPOINT(CreateDevice);
639 LOOKUP_LIBRESOC_ENTRYPOINT(EnumerateDeviceExtensionProperties);
640 LOOKUP_LIBRESOC_ENTRYPOINT(GetPhysicalDeviceSparseImageFormatProperties);
641
642
643 #undef LOOKUP_LIBRESOC_ENTRYPOINT
644
645 if (instance == NULL)
646 return NULL;
647
648 int idx = libresoc_get_instance_entrypoint_index(pName);
649 if (idx >= 0)
650 return instance->dispatch.entrypoints[idx];
651
652 idx = libresoc_get_physical_device_entrypoint_index(pName);
653 if (idx >= 0)
654 return instance->physical_device_dispatch.entrypoints[idx];
655
656 idx = libresoc_get_device_entrypoint_index(pName);
657 if (idx >= 0)
658 return instance->device_dispatch.entrypoints[idx];
659
660 return NULL;
661 }
662
663 /* With version 1+ of the loader interface the ICD should expose
664 * vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps.
665 */
666 PUBLIC
667 VKAPI_ATTR PFN_vkVoidFunction
668 VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance,
669 const char *pName);
670
671 PUBLIC
672 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
673 vk_icdGetInstanceProcAddr(VkInstance instance,
674 const char* pName)
675 {
676 if (getenv("LIBRESOC_TRACE")) {
677 fprintf(stderr, "vk_icdGetInstanceProcAddr called for: %s \n", pName);
678 }
679 return libresoc_GetInstanceProcAddr(instance, pName);
680 }
681
682 PFN_vkVoidFunction
683 libresoc_GetDeviceProcAddr(VkDevice _device,
684 const char *pName)
685 {
686 if (getenv("LIBRESOC_TRACE")) {
687 fprintf(stderr, "GetDeviceProcAddr called for: %s \n", pName);
688 }
689 LIBRESOC_FROM_HANDLE(libresoc_device, device, _device);
690
691 if (!device || !pName)
692 return NULL;
693
694 int idx = libresoc_get_device_entrypoint_index(pName);
695 if (idx < 0)
696 return NULL;
697
698 return device->dispatch.entrypoints[idx];
699 }
700
701 /* With version 4+ of the loader interface the ICD should expose
702 * vk_icdGetPhysicalDeviceProcAddr()
703 */
704 PUBLIC
705 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
706 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,
707 const char* pName);
708
709 PFN_vkVoidFunction
710 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,
711 const char* pName)
712 {
713 if (getenv("LIBRESOC_TRACE")) {
714 fprintf(stderr, "vk_icdGetPhysicalDeviceProcAddr called for: %s \n", pName);
715 }
716 LIBRESOC_FROM_HANDLE(libresoc_instance, instance, _instance);
717
718 if (!pName || !instance)
719 return NULL;
720
721 int idx = libresoc_get_physical_device_entrypoint_index(pName);
722 if (idx < 0)
723 return NULL;
724
725 return instance->physical_device_dispatch.entrypoints[idx];
726 }
727
728 VkResult
729 libresoc_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
730 const char *pLayerName,
731 uint32_t *pPropertyCount,
732 VkExtensionProperties *pProperties)
733 {
734 if (getenv("LIBRESOC_TRACE")) {
735 fprintf(stderr, "EnumerateDeviceExtensionProperties called for layer: %s \n", pLayerName);
736 }
737 LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice);
738 VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
739
740 for (int i = 0; i < LIBRESOC_DEVICE_EXTENSION_COUNT; i++) {
741 if (device->supported_extensions.extensions[i]) {
742 vk_outarray_append(&out, prop) {
743 *prop = libresoc_device_extensions[i];
744 }
745 }
746 }
747
748 return vk_outarray_status(&out);
749 }
750
751 static void
752 libresoc_device_init_dispatch(struct libresoc_device *device)
753 {
754 const struct libresoc_instance *instance = device->physical_device->instance;
755 const struct libresoc_device_dispatch_table *dispatch_table_layer = NULL;
756
757 for (unsigned i = 0; i < ARRAY_SIZE(device->dispatch.entrypoints); i++) {
758 /* Vulkan requires that entrypoints for extensions which have not been
759 * enabled must not be advertised.
760 */
761 if (!libresoc_device_entrypoint_is_enabled(i, instance->apiVersion,
762 &instance->enabled_extensions,
763 &device->enabled_extensions)) {
764 device->dispatch.entrypoints[i] = NULL;
765 } else if (dispatch_table_layer &&
766 dispatch_table_layer->entrypoints[i]) {
767 device->dispatch.entrypoints[i] =
768 dispatch_table_layer->entrypoints[i];
769 } else {
770 device->dispatch.entrypoints[i] =
771 libresoc_device_dispatch_table.entrypoints[i];
772 }
773 }
774 }
775
776 /*
777 static VkResult
778 libresoc_create_pthread_cond(pthread_cond_t *cond)
779 {
780 pthread_condattr_t condattr;
781 if (pthread_condattr_init(&condattr)) {
782 return VK_ERROR_INITIALIZATION_FAILED;
783 }
784
785 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) {
786 pthread_condattr_destroy(&condattr);
787 return VK_ERROR_INITIALIZATION_FAILED;
788 }
789 if (pthread_cond_init(cond, &condattr)) {
790 pthread_condattr_destroy(&condattr);
791 return VK_ERROR_INITIALIZATION_FAILED;
792 }
793 pthread_condattr_destroy(&condattr);
794 return VK_SUCCESS;
795 }
796 */
797 static VkResult
798 check_physical_device_features(VkPhysicalDevice physicalDevice,
799 const VkPhysicalDeviceFeatures *features)
800 {
801 LIBRESOC_FROM_HANDLE(libresoc_physical_device, physical_device, physicalDevice);
802 VkPhysicalDeviceFeatures supported_features;
803 libresoc_GetPhysicalDeviceFeatures(physicalDevice, &supported_features);
804 VkBool32 *supported_feature = (VkBool32 *)&supported_features;
805 VkBool32 *enabled_feature = (VkBool32 *)features;
806 unsigned num_features = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
807 for (uint32_t i = 0; i < num_features; i++) {
808 if (enabled_feature[i] && !supported_feature[i])
809 return vk_error(physical_device->instance, VK_ERROR_FEATURE_NOT_PRESENT);
810 }
811
812 return VK_SUCCESS;
813 }
814 static int libresoc_get_device_extension_index(const char *name)
815 {
816 for (unsigned i = 0; i < LIBRESOC_DEVICE_EXTENSION_COUNT; ++i) {
817 if (strcmp(name, libresoc_device_extensions[i].extensionName) == 0)
818 return i;
819 }
820 return -1;
821 }
822
823 static int
824 libresoc_queue_init(struct libresoc_device *device, struct libresoc_queue *queue,
825 uint32_t queue_family_index, int idx,
826 VkDeviceQueueCreateFlags flags,
827 const VkDeviceQueueGlobalPriorityCreateInfoEXT *global_priority)
828 {
829 queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
830 queue->device = device;
831 queue->queue_family_index = queue_family_index;
832 queue->queue_idx = idx;
833 queue->flags = flags;
834 return VK_SUCCESS;
835 }
836
837 static void
838 libresoc_queue_finish(struct libresoc_queue *queue)
839 {
840 //TODO: understand and enable following code
841 // if (queue->thread_running) {
842 // p_atomic_set(&queue->thread_exit, true);
843 // pthread_cond_broadcast(&queue->thread_cond);
844 // pthread_join(queue->submission_thread, NULL);
845 // }
846 // pthread_cond_destroy(&queue->thread_cond);
847 // pthread_mutex_destroy(&queue->pending_mutex);
848 // pthread_mutex_destroy(&queue->thread_mutex);
849 //
850 // if (queue->hw_ctx)
851 // queue->device->ws->ctx_destroy(queue->hw_ctx);
852 //
853 // if (queue->initial_full_flush_preamble_cs)
854 // queue->device->ws->cs_destroy(queue->initial_full_flush_preamble_cs);
855 // if (queue->initial_preamble_cs)
856 // queue->device->ws->cs_destroy(queue->initial_preamble_cs);
857 // if (queue->continue_preamble_cs)
858 // queue->device->ws->cs_destroy(queue->continue_preamble_cs);
859 // if (queue->descriptor_bo)
860 // queue->device->ws->buffer_destroy(queue->descriptor_bo);
861 // if (queue->scratch_bo)
862 // queue->device->ws->buffer_destroy(queue->scratch_bo);
863 // if (queue->esgs_ring_bo)
864 // queue->device->ws->buffer_destroy(queue->esgs_ring_bo);
865 // if (queue->gsvs_ring_bo)
866 // queue->device->ws->buffer_destroy(queue->gsvs_ring_bo);
867 // if (queue->tess_rings_bo)
868 // queue->device->ws->buffer_destroy(queue->tess_rings_bo);
869 // if (queue->gds_bo)
870 // queue->device->ws->buffer_destroy(queue->gds_bo);
871 // if (queue->gds_oa_bo)
872 // queue->device->ws->buffer_destroy(queue->gds_oa_bo);
873 // if (queue->compute_scratch_bo)
874 // queue->device->ws->buffer_destroy(queue->compute_scratch_bo);
875 }
876 VkResult
877 libresoc_CreateDevice(VkPhysicalDevice physicalDevice,
878 const VkDeviceCreateInfo *pCreateInfo,
879 const VkAllocationCallbacks *pAllocator,
880 VkDevice *pDevice)
881 {
882 if (getenv("LIBRESOC_TRACE")) {
883 fprintf(stderr, "CreateDevice called \n");
884 }
885 LIBRESOC_FROM_HANDLE(libresoc_physical_device, physical_device, physicalDevice);
886 VkResult result;
887 struct libresoc_device *device;
888
889 /* Check enabled features */
890 if (pCreateInfo->pEnabledFeatures) {
891 result = check_physical_device_features(physicalDevice,
892 pCreateInfo->pEnabledFeatures);
893 if (result != VK_SUCCESS)
894 return result;
895 }
896
897 device = vk_zalloc2(&physical_device->instance->alloc, pAllocator,
898 sizeof(*device), 8,
899 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
900 if (!device)
901 return vk_error(physical_device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
902
903 vk_device_init(&device->vk, pCreateInfo,
904 &physical_device->instance->alloc, pAllocator);
905
906 device->instance = physical_device->instance;
907 device->physical_device = physical_device;
908
909 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
910 const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i];
911 int index = libresoc_get_device_extension_index(ext_name);
912 if (index < 0 || !physical_device->supported_extensions.extensions[index]) {
913 vk_free(&device->vk.alloc, device);
914 return vk_error(physical_device->instance, VK_ERROR_EXTENSION_NOT_PRESENT);
915 }
916
917 device->enabled_extensions.extensions[index] = true;
918 }
919
920 libresoc_device_init_dispatch(device);
921
922 for (unsigned i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
923 const VkDeviceQueueCreateInfo *queue_create = &pCreateInfo->pQueueCreateInfos[i];
924 uint32_t qfi = queue_create->queueFamilyIndex;
925 const VkDeviceQueueGlobalPriorityCreateInfoEXT *global_priority =
926 vk_find_struct_const(queue_create->pNext, DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT);
927
928
929 device->queues[qfi] = vk_alloc(&device->vk.alloc,
930 queue_create->queueCount * sizeof(struct libresoc_queue), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
931 if (!device->queues[qfi]) {
932 result = VK_ERROR_OUT_OF_HOST_MEMORY;
933 goto fail;
934 }
935
936 memset(device->queues[qfi], 0, queue_create->queueCount * sizeof(struct libresoc_queue));
937
938 device->queue_count[qfi] = queue_create->queueCount;
939
940 for (unsigned q = 0; q < queue_create->queueCount; q++) {
941 result = libresoc_queue_init(device, &device->queues[qfi][q],
942 qfi, q, queue_create->flags,
943 global_priority);
944 if (result != VK_SUCCESS)
945 goto fail;
946 }
947 }
948
949 if (result != VK_SUCCESS)
950 goto fail;
951
952 VkPipelineCacheCreateInfo ci;
953 ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
954 ci.pNext = NULL;
955 ci.flags = 0;
956 ci.pInitialData = NULL;
957 ci.initialDataSize = 0;
958 VkPipelineCache pc;
959 result = libresoc_CreatePipelineCache(libresoc_device_to_handle(device),
960 &ci, NULL, &pc);
961 if (result != VK_SUCCESS)
962 goto fail;
963
964 *pDevice = libresoc_device_to_handle(device);
965 return VK_SUCCESS;
966
967 fail:
968 libresoc_DestroyPipelineCache(libresoc_device_to_handle(device), pc, NULL);
969 for (unsigned i = 0; i < LIBRESOC_MAX_QUEUE_FAMILIES; i++) {
970 for (unsigned q = 0; q < device->queue_count[i]; q++)
971 libresoc_queue_finish(&device->queues[i][q]);
972 if (device->queue_count[i])
973 vk_free(&device->vk.alloc, device->queues[i]);
974 }
975
976 vk_free(&device->vk.alloc, device);
977 return result;
978 }
979
980 void
981 libresoc_DestroyDevice(VkDevice _device,
982 const VkAllocationCallbacks *pAllocator)
983 {
984 if (getenv("LIBRESOC_TRACE")) {
985 fprintf(stderr, "DestroyDevice called. \n");
986 }
987 /* FIXME: stub */
988 }
989
990 void libresoc_GetDeviceQueue(
991 VkDevice _device,
992 uint32_t queueFamilyIndex,
993 uint32_t queueIndex,
994 VkQueue* pQueue)
995 {
996 if (getenv("LIBRESOC_TRACE")) {
997 fprintf(stderr, "GetDeviceQueue called. \n");
998 }
999 LIBRESOC_FROM_HANDLE(libresoc_device, device, _device);
1000 struct libresoc_queue *queue;
1001
1002 queue = &device->queues[queueFamilyIndex][queueIndex];
1003 *pQueue = libresoc_queue_to_handle(queue);
1004 }