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 <fcntl.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <sys/mman.h>
29 #include <sys/sysinfo.h>
30 #include <unistd.h>
31 #include <xf86drm.h>
32
33 #include "v3dv_private.h"
34
35 #include "common/v3d_debug.h"
36
37 #include "broadcom/cle/v3dx_pack.h"
38
39 #include "compiler/v3d_compiler.h"
40 #include "compiler/glsl_types.h"
41
42 #include "drm-uapi/v3d_drm.h"
43 #include "format/u_format.h"
44 #include "vk_util.h"
45
46 #include "util/build_id.h"
47 #include "util/debug.h"
48
49 #ifdef VK_USE_PLATFORM_XCB_KHR
50 #include <xcb/xcb.h>
51 #include <xcb/dri3.h>
52 #endif
53
54 #ifdef USE_V3D_SIMULATOR
55 #include "drm-uapi/i915_drm.h"
56 #endif
57
58 static void *
default_alloc_func(void * pUserData,size_t size,size_t align,VkSystemAllocationScope allocationScope)59 default_alloc_func(void *pUserData, size_t size, size_t align,
60 VkSystemAllocationScope allocationScope)
61 {
62 return malloc(size);
63 }
64
65 static void *
default_realloc_func(void * pUserData,void * pOriginal,size_t size,size_t align,VkSystemAllocationScope allocationScope)66 default_realloc_func(void *pUserData, void *pOriginal, size_t size,
67 size_t align, VkSystemAllocationScope allocationScope)
68 {
69 return realloc(pOriginal, size);
70 }
71
72 static void
default_free_func(void * pUserData,void * pMemory)73 default_free_func(void *pUserData, void *pMemory)
74 {
75 free(pMemory);
76 }
77
78 static const VkAllocationCallbacks default_alloc = {
79 .pUserData = NULL,
80 .pfnAllocation = default_alloc_func,
81 .pfnReallocation = default_realloc_func,
82 .pfnFree = default_free_func,
83 };
84
85 VkResult
v3dv_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)86 v3dv_EnumerateInstanceExtensionProperties(const char *pLayerName,
87 uint32_t *pPropertyCount,
88 VkExtensionProperties *pProperties)
89 {
90 /* We don't support any layers */
91 if (pLayerName)
92 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
93
94 VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
95
96 for (int i = 0; i < V3DV_INSTANCE_EXTENSION_COUNT; i++) {
97 if (v3dv_instance_extensions_supported.extensions[i]) {
98 vk_outarray_append(&out, prop) {
99 *prop = v3dv_instance_extensions[i];
100 }
101 }
102 }
103
104 return vk_outarray_status(&out);
105 }
106
107 VkResult
v3dv_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)108 v3dv_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
109 const VkAllocationCallbacks *pAllocator,
110 VkInstance *pInstance)
111 {
112 struct v3dv_instance *instance;
113 VkResult result;
114
115 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
116
117 struct v3dv_instance_extension_table enabled_extensions = {};
118 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
119 int idx;
120 for (idx = 0; idx < V3DV_INSTANCE_EXTENSION_COUNT; idx++) {
121 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
122 v3dv_instance_extensions[idx].extensionName) == 0)
123 break;
124 }
125
126 if (idx >= V3DV_INSTANCE_EXTENSION_COUNT)
127 return vk_error(NULL, VK_ERROR_EXTENSION_NOT_PRESENT);
128
129 if (!v3dv_instance_extensions_supported.extensions[idx])
130 return vk_error(NULL, VK_ERROR_EXTENSION_NOT_PRESENT);
131
132 enabled_extensions.extensions[idx] = true;
133 }
134
135 instance = vk_alloc2(&default_alloc, pAllocator, sizeof(*instance), 8,
136 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
137 if (!instance)
138 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
139
140 instance->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
141
142 if (pAllocator)
143 instance->alloc = *pAllocator;
144 else
145 instance->alloc = default_alloc;
146
147 v3d_process_debug_variable();
148
149 instance->app_info = (struct v3dv_app_info) { .api_version = 0 };
150 if (pCreateInfo->pApplicationInfo) {
151 const VkApplicationInfo *app = pCreateInfo->pApplicationInfo;
152
153 instance->app_info.app_name =
154 vk_strdup(&instance->alloc, app->pApplicationName,
155 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
156 instance->app_info.app_version = app->applicationVersion;
157
158 instance->app_info.engine_name =
159 vk_strdup(&instance->alloc, app->pEngineName,
160 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
161 instance->app_info.engine_version = app->engineVersion;
162
163 instance->app_info.api_version = app->apiVersion;
164 }
165
166 if (instance->app_info.api_version == 0)
167 instance->app_info.api_version = VK_API_VERSION_1_0;
168
169 instance->enabled_extensions = enabled_extensions;
170
171 for (unsigned i = 0; i < ARRAY_SIZE(instance->dispatch.entrypoints); i++) {
172 /* Vulkan requires that entrypoints for extensions which have not been
173 * enabled must not be advertised.
174 */
175 if (!v3dv_instance_entrypoint_is_enabled(i,
176 instance->app_info.api_version,
177 &instance->enabled_extensions)) {
178 instance->dispatch.entrypoints[i] = NULL;
179 } else {
180 instance->dispatch.entrypoints[i] =
181 v3dv_instance_dispatch_table.entrypoints[i];
182 }
183 }
184
185 struct v3dv_physical_device *pdevice = &instance->physicalDevice;
186 for (unsigned i = 0; i < ARRAY_SIZE(pdevice->dispatch.entrypoints); i++) {
187 /* Vulkan requires that entrypoints for extensions which have not been
188 * enabled must not be advertised.
189 */
190 if (!v3dv_physical_device_entrypoint_is_enabled(i,
191 instance->app_info.api_version,
192 &instance->enabled_extensions)) {
193 pdevice->dispatch.entrypoints[i] = NULL;
194 } else {
195 pdevice->dispatch.entrypoints[i] =
196 v3dv_physical_device_dispatch_table.entrypoints[i];
197 }
198 }
199
200 for (unsigned i = 0; i < ARRAY_SIZE(instance->device_dispatch.entrypoints); i++) {
201 /* Vulkan requires that entrypoints for extensions which have not been
202 * enabled must not be advertised.
203 */
204 if (!v3dv_device_entrypoint_is_enabled(i,
205 instance->app_info.api_version,
206 &instance->enabled_extensions,
207 NULL)) {
208 instance->device_dispatch.entrypoints[i] = NULL;
209 } else {
210 instance->device_dispatch.entrypoints[i] =
211 v3dv_device_dispatch_table.entrypoints[i];
212 }
213 }
214
215 instance->physicalDeviceCount = -1;
216
217 result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
218 if (result != VK_SUCCESS) {
219 vk_free2(&default_alloc, pAllocator, instance);
220 return vk_error(NULL, result);
221 }
222
223
224 /* We start with the default values for the pipeline_cache envvars */
225 instance->pipeline_cache_enabled = true;
226 instance->default_pipeline_cache_enabled = true;
227 const char *pipeline_cache_str = getenv("V3DV_ENABLE_PIPELINE_CACHE");
228 if (pipeline_cache_str != NULL) {
229 if (strncmp(pipeline_cache_str, "full", 4) == 0) {
230 /* nothing to do, just to filter correct values */
231 } else if (strncmp(pipeline_cache_str, "no-default-cache", 16) == 0) {
232 instance->default_pipeline_cache_enabled = false;
233 } else if (strncmp(pipeline_cache_str, "off", 3) == 0) {
234 instance->pipeline_cache_enabled = false;
235 instance->default_pipeline_cache_enabled = false;
236 } else {
237 fprintf(stderr, "Wrong value for envvar V3DV_ENABLE_PIPELINE_CACHE. "
238 "Allowed values are: full, no-default-cache, off\n");
239 }
240 }
241
242 if (instance->pipeline_cache_enabled == false) {
243 fprintf(stderr, "WARNING: v3dv pipeline cache is disabled. Performance "
244 "can be affected negatively\n");
245 } else {
246 if (instance->default_pipeline_cache_enabled == false) {
247 fprintf(stderr, "WARNING: default v3dv pipeline cache is disabled. "
248 "Performance can be affected negatively\n");
249 }
250 }
251
252 glsl_type_singleton_init_or_ref();
253
254 VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
255
256 *pInstance = v3dv_instance_to_handle(instance);
257
258 return VK_SUCCESS;
259 }
260
261 static void
physical_device_finish(struct v3dv_physical_device * device)262 physical_device_finish(struct v3dv_physical_device *device)
263 {
264 v3dv_wsi_finish(device);
265
266 v3d_compiler_free(device->compiler);
267
268 close(device->render_fd);
269 if (device->display_fd >= 0)
270 close(device->display_fd);
271
272 free(device->name);
273
274 #if using_v3d_simulator
275 v3d_simulator_destroy(device->sim_file);
276 #endif
277 }
278
279 void
v3dv_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)280 v3dv_DestroyInstance(VkInstance _instance,
281 const VkAllocationCallbacks *pAllocator)
282 {
283 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
284
285 if (!instance)
286 return;
287
288 if (instance->physicalDeviceCount > 0) {
289 /* We support at most one physical device. */
290 assert(instance->physicalDeviceCount == 1);
291 physical_device_finish(&instance->physicalDevice);
292 }
293
294 vk_free(&instance->alloc, (char *)instance->app_info.app_name);
295 vk_free(&instance->alloc, (char *)instance->app_info.engine_name);
296
297 VG(VALGRIND_DESTROY_MEMPOOL(instance));
298
299 vk_debug_report_instance_destroy(&instance->debug_report_callbacks);
300
301 glsl_type_singleton_decref();
302
303 vk_free(&instance->alloc, instance);
304 }
305
306 static uint64_t
compute_heap_size()307 compute_heap_size()
308 {
309 #if !using_v3d_simulator
310 /* Query the total ram from the system */
311 struct sysinfo info;
312 sysinfo(&info);
313
314 uint64_t total_ram = (uint64_t)info.totalram * (uint64_t)info.mem_unit;
315 #else
316 uint64_t total_ram = (uint64_t) v3d_simulator_get_mem_size();
317 #endif
318
319 /* We don't want to burn too much ram with the GPU. If the user has 4GiB
320 * or less, we use at most half. If they have more than 4GiB, we use 3/4.
321 */
322 uint64_t available_ram;
323 if (total_ram <= 4ull * 1024ull * 1024ull * 1024ull)
324 available_ram = total_ram / 2;
325 else
326 available_ram = total_ram * 3 / 4;
327
328 return available_ram;
329 }
330
331 /* When running on the simulator we do everything on a single render node so
332 * we don't need to get an authenticated display fd from the display server.
333 */
334 #if !using_v3d_simulator
335 #ifdef VK_USE_PLATFORM_XCB_KHR
336 static int
create_display_fd_xcb()337 create_display_fd_xcb()
338 {
339 int fd = -1;
340
341 xcb_connection_t *conn = xcb_connect(NULL, NULL);
342 if (xcb_connection_has_error(conn))
343 goto finish;
344
345 const xcb_setup_t *setup = xcb_get_setup(conn);
346 xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
347 xcb_screen_t *screen = iter.data;
348
349 xcb_dri3_open_cookie_t cookie;
350 xcb_dri3_open_reply_t *reply;
351 cookie = xcb_dri3_open(conn, screen->root, None);
352 reply = xcb_dri3_open_reply(conn, cookie, NULL);
353 if (!reply)
354 goto finish;
355
356 if (reply->nfd != 1)
357 goto finish;
358
359 fd = xcb_dri3_open_reply_fds(conn, reply)[0];
360 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
361
362 finish:
363 xcb_disconnect(conn);
364 if (reply)
365 free(reply);
366
367 return fd;
368 }
369 #endif
370 #endif
371
372 static bool
v3d_has_feature(struct v3dv_physical_device * device,enum drm_v3d_param feature)373 v3d_has_feature(struct v3dv_physical_device *device, enum drm_v3d_param feature)
374 {
375 struct drm_v3d_get_param p = {
376 .param = feature,
377 };
378 if (v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_PARAM, &p) != 0)
379 return false;
380 return p.value;
381 }
382
383 static bool
device_has_expected_features(struct v3dv_physical_device * device)384 device_has_expected_features(struct v3dv_physical_device *device)
385 {
386 return v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_TFU) &&
387 v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CSD) &&
388 v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH);
389 }
390
391
392 static VkResult
init_uuids(struct v3dv_physical_device * device)393 init_uuids(struct v3dv_physical_device *device)
394 {
395 const struct build_id_note *note =
396 build_id_find_nhdr_for_addr(init_uuids);
397 if (!note) {
398 return vk_errorf(device->instance,
399 VK_ERROR_INITIALIZATION_FAILED,
400 "Failed to find build-id");
401 }
402
403 unsigned build_id_len = build_id_length(note);
404 if (build_id_len < 20) {
405 return vk_errorf(device->instance,
406 VK_ERROR_INITIALIZATION_FAILED,
407 "build-id too short. It needs to be a SHA");
408 }
409
410 uint32_t vendor_id = v3dv_physical_device_vendor_id(device);
411 uint32_t device_id = v3dv_physical_device_device_id(device);
412
413 struct mesa_sha1 sha1_ctx;
414 uint8_t sha1[20];
415 STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1));
416
417 /* The pipeline cache UUID is used for determining when a pipeline cache is
418 * invalid. It needs both a driver build and the PCI ID of the device.
419 */
420 _mesa_sha1_init(&sha1_ctx);
421 _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);
422 _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
423 _mesa_sha1_final(&sha1_ctx, sha1);
424 memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
425
426 /* The driver UUID is used for determining sharability of images and memory
427 * between two Vulkan instances in separate processes. People who want to
428 * share memory need to also check the device UUID (below) so all this
429 * needs to be is the build-id.
430 */
431 memcpy(device->driver_uuid, build_id_data(note), VK_UUID_SIZE);
432
433 /* The device UUID uniquely identifies the given device within the machine.
434 * Since we never have more than one device, this doesn't need to be a real
435 * UUID.
436 */
437 _mesa_sha1_init(&sha1_ctx);
438 _mesa_sha1_update(&sha1_ctx, &vendor_id, sizeof(vendor_id));
439 _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
440 _mesa_sha1_final(&sha1_ctx, sha1);
441 memcpy(device->device_uuid, sha1, VK_UUID_SIZE);
442
443 return VK_SUCCESS;
444 }
445
446 static VkResult
physical_device_init(struct v3dv_physical_device * device,struct v3dv_instance * instance,drmDevicePtr drm_device)447 physical_device_init(struct v3dv_physical_device *device,
448 struct v3dv_instance *instance,
449 drmDevicePtr drm_device)
450 {
451 VkResult result = VK_SUCCESS;
452 int32_t display_fd = -1;
453
454 device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
455 device->instance = instance;
456
457 const char *path = drm_device->nodes[DRM_NODE_RENDER];
458 int32_t render_fd = open(path, O_RDWR | O_CLOEXEC);
459 if (render_fd < 0)
460 return vk_error(instance, VK_ERROR_INCOMPATIBLE_DRIVER);
461
462 /* If we are running on real hardware we need to open the vc4 display
463 * device so we can allocate winsys BOs for the v3d core to render into.
464 */
465 #if !using_v3d_simulator
466 #ifdef VK_USE_PLATFORM_XCB_KHR
467 display_fd = create_display_fd_xcb();
468 #endif
469
470 if (display_fd == -1) {
471 result = VK_ERROR_INCOMPATIBLE_DRIVER;
472 goto fail;
473 }
474 #endif
475
476 device->render_fd = render_fd; /* The v3d render node */
477 device->display_fd = display_fd; /* The vc4 primary node */
478
479 #if using_v3d_simulator
480 device->sim_file = v3d_simulator_init(device->render_fd);
481 #endif
482
483 if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {
484 result = VK_ERROR_INCOMPATIBLE_DRIVER;
485 goto fail;
486 }
487
488 if (device->devinfo.ver < 42) {
489 result = VK_ERROR_INCOMPATIBLE_DRIVER;
490 goto fail;
491 }
492
493 if (!device_has_expected_features(device)) {
494 result = VK_ERROR_INCOMPATIBLE_DRIVER;
495 goto fail;
496 }
497
498 result = init_uuids(device);
499 if (result != VK_SUCCESS)
500 goto fail;
501
502 device->compiler = v3d_compiler_init(&device->devinfo);
503 device->next_program_id = 0;
504
505 asprintf(&device->name, "V3D %d.%d",
506 device->devinfo.ver / 10, device->devinfo.ver % 10);
507
508 /* Setup available memory heaps and types */
509 VkPhysicalDeviceMemoryProperties *mem = &device->memory;
510 mem->memoryHeapCount = 1;
511 mem->memoryHeaps[0].size = compute_heap_size();
512 mem->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
513
514 /* This is the only combination required by the spec */
515 mem->memoryTypeCount = 1;
516 mem->memoryTypes[0].propertyFlags =
517 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
518 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
519 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
520 mem->memoryTypes[0].heapIndex = 0;
521
522 device->options.merge_jobs = getenv("V3DV_NO_MERGE_JOBS") == NULL;
523
524 result = v3dv_wsi_init(device);
525 if (result != VK_SUCCESS) {
526 vk_error(instance, result);
527 goto fail;
528 }
529
530 v3dv_physical_device_get_supported_extensions(device,
531 &device->supported_extensions);
532
533 fprintf(stderr, "WARNING: v3dv is neither a complete nor a conformant "
534 "Vulkan implementation. Testing use only.\n");
535
536 return VK_SUCCESS;
537
538 fail:
539 if (render_fd >= 0)
540 close(render_fd);
541 if (display_fd >= 0)
542 close(display_fd);
543
544 return result;
545 }
546
547 static VkResult
enumerate_devices(struct v3dv_instance * instance)548 enumerate_devices(struct v3dv_instance *instance)
549 {
550 /* TODO: Check for more devices? */
551 drmDevicePtr devices[8];
552 VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
553 int max_devices;
554
555 instance->physicalDeviceCount = 0;
556
557 max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
558 if (max_devices < 1)
559 return VK_ERROR_INCOMPATIBLE_DRIVER;
560
561 #if !using_v3d_simulator
562 int32_t v3d_idx = -1;
563 int32_t vc4_idx = -1;
564 #endif
565 for (unsigned i = 0; i < (unsigned)max_devices; i++) {
566 #if using_v3d_simulator
567 /* In the simulator, we look for an Intel render node */
568 if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
569 devices[i]->bustype == DRM_BUS_PCI &&
570 devices[i]->deviceinfo.pci->vendor_id == 0x8086) {
571 result = physical_device_init(&instance->physicalDevice, instance,
572 devices[i]);
573 if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
574 break;
575 }
576 #else
577 /* On actual hardware, we should have a render node (v3d)
578 * and a primary node (vc4). We will need to use the primary
579 * to allocate WSI buffers and share them with the render node
580 * via prime, but that is a privileged operation so we need the
581 * primary node to be authenticated, and for that we need the
582 * display server to provide the device fd (with DRI3), so we
583 * here we only check that the device is present but we don't
584 * try to open it.
585 */
586 if (devices[i]->bustype != DRM_BUS_PLATFORM)
587 continue;
588
589 if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER) {
590 char **compat = devices[i]->deviceinfo.platform->compatible;
591 while (*compat) {
592 if (strncmp(*compat, "brcm,2711-v3d", 13) == 0) {
593 v3d_idx = i;
594 break;
595 }
596 compat++;
597 }
598 } else if (devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY) {
599 char **compat = devices[i]->deviceinfo.platform->compatible;
600 while (*compat) {
601 if (strncmp(*compat, "brcm,bcm2711-vc5", 16) == 0 ||
602 strncmp(*compat, "brcm,bcm2835-vc4", 16) == 0 ) {
603 vc4_idx = i;
604 break;
605 }
606 compat++;
607 }
608 }
609 #endif
610 }
611
612 #if !using_v3d_simulator
613 if (v3d_idx == -1 || vc4_idx == -1)
614 result = VK_ERROR_INCOMPATIBLE_DRIVER;
615 else
616 result = physical_device_init(&instance->physicalDevice, instance,
617 devices[v3d_idx]);
618 #endif
619
620 drmFreeDevices(devices, max_devices);
621
622 if (result == VK_SUCCESS)
623 instance->physicalDeviceCount = 1;
624
625 return result;
626 }
627
628 static VkResult
instance_ensure_physical_device(struct v3dv_instance * instance)629 instance_ensure_physical_device(struct v3dv_instance *instance)
630 {
631 if (instance->physicalDeviceCount < 0) {
632 VkResult result = enumerate_devices(instance);
633 if (result != VK_SUCCESS &&
634 result != VK_ERROR_INCOMPATIBLE_DRIVER)
635 return result;
636 }
637
638 return VK_SUCCESS;
639 }
640
641 VkResult
v3dv_EnumeratePhysicalDevices(VkInstance _instance,uint32_t * pPhysicalDeviceCount,VkPhysicalDevice * pPhysicalDevices)642 v3dv_EnumeratePhysicalDevices(VkInstance _instance,
643 uint32_t *pPhysicalDeviceCount,
644 VkPhysicalDevice *pPhysicalDevices)
645 {
646 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
647 VK_OUTARRAY_MAKE(out, pPhysicalDevices, pPhysicalDeviceCount);
648
649 VkResult result = instance_ensure_physical_device(instance);
650 if (result != VK_SUCCESS)
651 return result;
652
653 if (instance->physicalDeviceCount == 0)
654 return VK_SUCCESS;
655
656 assert(instance->physicalDeviceCount == 1);
657 vk_outarray_append(&out, i) {
658 *i = v3dv_physical_device_to_handle(&instance->physicalDevice);
659 }
660
661 return vk_outarray_status(&out);
662 }
663
664 void
v3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures * pFeatures)665 v3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
666 VkPhysicalDeviceFeatures *pFeatures)
667 {
668 memset(pFeatures, 0, sizeof(*pFeatures));
669
670 *pFeatures = (VkPhysicalDeviceFeatures) {
671 .robustBufferAccess = true, /* This feature is mandatory */
672 .fullDrawIndexUint32 = false, /* Only available since V3D 4.4.9.1 */
673 .imageCubeArray = true,
674 .independentBlend = true,
675 .geometryShader = false,
676 .tessellationShader = false,
677 .sampleRateShading = true,
678 .dualSrcBlend = false,
679 .logicOp = true,
680 .multiDrawIndirect = false,
681 .drawIndirectFirstInstance = true,
682 .depthClamp = false,
683 .depthBiasClamp = false,
684 .fillModeNonSolid = true,
685 .depthBounds = false, /* Only available since V3D 4.3.16.2 */
686 .wideLines = true,
687 .largePoints = true,
688 .alphaToOne = true,
689 .multiViewport = false,
690 .samplerAnisotropy = true,
691 .textureCompressionETC2 = true,
692 .textureCompressionASTC_LDR = false,
693 .textureCompressionBC = false,
694 .occlusionQueryPrecise = true,
695 .pipelineStatisticsQuery = false,
696 .vertexPipelineStoresAndAtomics = true,
697 .fragmentStoresAndAtomics = true,
698 .shaderTessellationAndGeometryPointSize = false,
699 .shaderImageGatherExtended = false,
700 .shaderStorageImageExtendedFormats = true,
701 .shaderStorageImageMultisample = false,
702 .shaderStorageImageReadWithoutFormat = false,
703 .shaderStorageImageWriteWithoutFormat = false,
704 .shaderUniformBufferArrayDynamicIndexing = false,
705 .shaderSampledImageArrayDynamicIndexing = false,
706 .shaderStorageBufferArrayDynamicIndexing = false,
707 .shaderStorageImageArrayDynamicIndexing = false,
708 .shaderClipDistance = true,
709 .shaderCullDistance = false,
710 .shaderFloat64 = false,
711 .shaderInt64 = false,
712 .shaderInt16 = false,
713 .shaderResourceResidency = false,
714 .shaderResourceMinLod = false,
715 .sparseBinding = false,
716 .sparseResidencyBuffer = false,
717 .sparseResidencyImage2D = false,
718 .sparseResidencyImage3D = false,
719 .sparseResidency2Samples = false,
720 .sparseResidency4Samples = false,
721 .sparseResidency8Samples = false,
722 .sparseResidency16Samples = false,
723 .sparseResidencyAliased = false,
724 .variableMultisampleRate = false,
725 .inheritedQueries = true,
726 };
727 }
728
729 void
v3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures2 * pFeatures)730 v3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
731 VkPhysicalDeviceFeatures2 *pFeatures)
732 {
733 v3dv_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
734
735 vk_foreach_struct(ext, pFeatures->pNext) {
736 switch (ext->sType) {
737 default:
738 v3dv_debug_ignored_stype(ext->sType);
739 break;
740 }
741 }
742 }
743
744 uint32_t
v3dv_physical_device_vendor_id(struct v3dv_physical_device * dev)745 v3dv_physical_device_vendor_id(struct v3dv_physical_device *dev)
746 {
747 return 0x14E4; /* Broadcom */
748 }
749
750
751 #if using_v3d_simulator
752 static bool
get_i915_param(int fd,uint32_t param,int * value)753 get_i915_param(int fd, uint32_t param, int *value)
754 {
755 int tmp;
756
757 struct drm_i915_getparam gp = {
758 .param = param,
759 .value = &tmp,
760 };
761
762 int ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
763 if (ret != 0)
764 return false;
765
766 *value = tmp;
767 return true;
768 }
769 #endif
770
771 uint32_t
v3dv_physical_device_device_id(struct v3dv_physical_device * dev)772 v3dv_physical_device_device_id(struct v3dv_physical_device *dev)
773 {
774 #if using_v3d_simulator
775 int devid = 0;
776
777 if (!get_i915_param(dev->render_fd, I915_PARAM_CHIPSET_ID, &devid))
778 fprintf(stderr, "Error getting device_id\n");
779
780 return devid;
781 #else
782 return dev->devinfo.ver;
783 #endif
784 }
785
786 void
v3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,VkPhysicalDeviceProperties * pProperties)787 v3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
788 VkPhysicalDeviceProperties *pProperties)
789 {
790 V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
791
792 const uint32_t page_size = 4096;
793 const uint32_t mem_size = compute_heap_size();
794
795 /* Per-stage limits */
796 const uint32_t max_samplers = 16;
797 const uint32_t max_uniform_buffers = 12;
798 const uint32_t max_storage_buffers = 12;
799 const uint32_t max_dynamic_storage_buffers = 6;
800 const uint32_t max_sampled_images = 16;
801 const uint32_t max_storage_images = 4;
802 const uint32_t max_input_attachments = 4;
803 assert(max_sampled_images + max_storage_images + max_input_attachments
804 <= V3D_MAX_TEXTURE_SAMPLERS);
805
806 const uint32_t max_varying_components = 16 * 4;
807 const uint32_t max_render_targets = 4;
808
809 const uint32_t v3d_coord_shift = 6;
810
811 const uint32_t v3d_point_line_granularity = 2.0f / (1 << v3d_coord_shift);
812 const uint32_t max_fb_size = 4096;
813
814 const VkSampleCountFlags supported_sample_counts =
815 VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
816
817 struct timespec clock_res;
818 clock_getres(CLOCK_MONOTONIC, &clock_res);
819 const float timestamp_period =
820 clock_res.tv_sec * 1000000000.0f + clock_res.tv_nsec;
821
822 /* FIXME: this will probably require an in-depth review */
823 VkPhysicalDeviceLimits limits = {
824 .maxImageDimension1D = 4096,
825 .maxImageDimension2D = 4096,
826 .maxImageDimension3D = 4096,
827 .maxImageDimensionCube = 4096,
828 .maxImageArrayLayers = 2048,
829 .maxTexelBufferElements = (1ul << 28),
830 .maxUniformBufferRange = (1ul << 27),
831 .maxStorageBufferRange = (1ul << 27),
832 .maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE,
833 .maxMemoryAllocationCount = mem_size / page_size,
834 .maxSamplerAllocationCount = 64 * 1024,
835 .bufferImageGranularity = 256, /* A cache line */
836 .sparseAddressSpaceSize = 0,
837 .maxBoundDescriptorSets = MAX_SETS,
838 .maxPerStageDescriptorSamplers = max_samplers,
839 .maxPerStageDescriptorUniformBuffers = max_uniform_buffers,
840 .maxPerStageDescriptorStorageBuffers = max_storage_buffers,
841 .maxPerStageDescriptorSampledImages = max_sampled_images,
842 .maxPerStageDescriptorStorageImages = max_storage_images,
843 .maxPerStageDescriptorInputAttachments = max_input_attachments,
844 .maxPerStageResources = 128,
845
846 /* We multiply some limits by 6 to account for all shader stages */
847 .maxDescriptorSetSamplers = 6 * max_samplers,
848 .maxDescriptorSetUniformBuffers = 6 * max_uniform_buffers,
849 .maxDescriptorSetUniformBuffersDynamic = 8,
850 .maxDescriptorSetStorageBuffers = 6 * max_storage_buffers,
851 .maxDescriptorSetStorageBuffersDynamic = 6 * max_dynamic_storage_buffers,
852 .maxDescriptorSetSampledImages = 6 * max_sampled_images,
853 .maxDescriptorSetStorageImages = 6 * max_storage_images,
854 .maxDescriptorSetInputAttachments = 4,
855
856 /* Vertex limits */
857 .maxVertexInputAttributes = MAX_VERTEX_ATTRIBS,
858 .maxVertexInputBindings = MAX_VBS,
859 .maxVertexInputAttributeOffset = 0xffffffff,
860 .maxVertexInputBindingStride = 0xffffffff,
861 .maxVertexOutputComponents = max_varying_components,
862
863 /* Tessellation limits */
864 .maxTessellationGenerationLevel = 0,
865 .maxTessellationPatchSize = 0,
866 .maxTessellationControlPerVertexInputComponents = 0,
867 .maxTessellationControlPerVertexOutputComponents = 0,
868 .maxTessellationControlPerPatchOutputComponents = 0,
869 .maxTessellationControlTotalOutputComponents = 0,
870 .maxTessellationEvaluationInputComponents = 0,
871 .maxTessellationEvaluationOutputComponents = 0,
872
873 /* Geometry limits */
874 .maxGeometryShaderInvocations = 0,
875 .maxGeometryInputComponents = 0,
876 .maxGeometryOutputComponents = 0,
877 .maxGeometryOutputVertices = 0,
878 .maxGeometryTotalOutputComponents = 0,
879
880 /* Fragment limits */
881 .maxFragmentInputComponents = max_varying_components,
882 .maxFragmentOutputAttachments = 4,
883 .maxFragmentDualSrcAttachments = 0,
884 .maxFragmentCombinedOutputResources = max_render_targets +
885 max_storage_buffers +
886 max_storage_images,
887
888 /* Compute limits */
889 .maxComputeSharedMemorySize = 16384,
890 .maxComputeWorkGroupCount = { 65535, 65535, 65535 },
891 .maxComputeWorkGroupInvocations = 256,
892 .maxComputeWorkGroupSize = { 256, 256, 256 },
893
894 .subPixelPrecisionBits = v3d_coord_shift,
895 .subTexelPrecisionBits = 8,
896 .mipmapPrecisionBits = 8,
897 .maxDrawIndexedIndexValue = 0x00ffffff,
898 .maxDrawIndirectCount = 0x7fffffff,
899 .maxSamplerLodBias = 14.0f,
900 .maxSamplerAnisotropy = 16.0f,
901 .maxViewports = MAX_VIEWPORTS,
902 .maxViewportDimensions = { max_fb_size, max_fb_size },
903 .viewportBoundsRange = { -2.0 * max_fb_size,
904 2.0 * max_fb_size - 1 },
905 .viewportSubPixelBits = 0,
906 .minMemoryMapAlignment = page_size,
907 .minTexelBufferOffsetAlignment = VC5_UIFBLOCK_SIZE,
908 .minUniformBufferOffsetAlignment = 32,
909 .minStorageBufferOffsetAlignment = 32,
910 .minTexelOffset = -8,
911 .maxTexelOffset = 7,
912 .minTexelGatherOffset = -8,
913 .maxTexelGatherOffset = 7,
914 .minInterpolationOffset = -0.5,
915 .maxInterpolationOffset = 0.5,
916 .subPixelInterpolationOffsetBits = v3d_coord_shift,
917 .maxFramebufferWidth = max_fb_size,
918 .maxFramebufferHeight = max_fb_size,
919 .maxFramebufferLayers = 256,
920 .framebufferColorSampleCounts = supported_sample_counts,
921 .framebufferDepthSampleCounts = supported_sample_counts,
922 .framebufferStencilSampleCounts = supported_sample_counts,
923 .framebufferNoAttachmentsSampleCounts = supported_sample_counts,
924 .maxColorAttachments = max_render_targets,
925 .sampledImageColorSampleCounts = supported_sample_counts,
926 .sampledImageIntegerSampleCounts = supported_sample_counts,
927 .sampledImageDepthSampleCounts = supported_sample_counts,
928 .sampledImageStencilSampleCounts = supported_sample_counts,
929 .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT,
930 .maxSampleMaskWords = 1,
931 .timestampComputeAndGraphics = true,
932 .timestampPeriod = timestamp_period,
933 .maxClipDistances = 8,
934 .maxCullDistances = 0,
935 .maxCombinedClipAndCullDistances = 8,
936 .discreteQueuePriorities = 2,
937 .pointSizeRange = { v3d_point_line_granularity,
938 V3D_MAX_POINT_SIZE },
939 .lineWidthRange = { 1.0f, V3D_MAX_LINE_WIDTH },
940 .pointSizeGranularity = v3d_point_line_granularity,
941 .lineWidthGranularity = v3d_point_line_granularity,
942 .strictLines = true,
943 .standardSampleLocations = false,
944 .optimalBufferCopyOffsetAlignment = 32,
945 .optimalBufferCopyRowPitchAlignment = 32,
946 .nonCoherentAtomSize = 256,
947 };
948
949 *pProperties = (VkPhysicalDeviceProperties) {
950 .apiVersion = v3dv_physical_device_api_version(pdevice),
951 .driverVersion = vk_get_driver_version(),
952 .vendorID = v3dv_physical_device_vendor_id(pdevice),
953 .deviceID = v3dv_physical_device_device_id(pdevice),
954 .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
955 .limits = limits,
956 .sparseProperties = { 0 },
957 };
958
959 snprintf(pProperties->deviceName, sizeof(pProperties->deviceName),
960 "%s", pdevice->name);
961 memcpy(pProperties->pipelineCacheUUID,
962 pdevice->pipeline_cache_uuid, VK_UUID_SIZE);
963 }
964
965 void
v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceProperties2 * pProperties)966 v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
967 VkPhysicalDeviceProperties2 *pProperties)
968 {
969 V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
970
971 v3dv_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
972
973 vk_foreach_struct(ext, pProperties->pNext) {
974 switch (ext->sType) {
975 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
976 VkPhysicalDeviceIDProperties *id_props =
977 (VkPhysicalDeviceIDProperties *)ext;
978 memcpy(id_props->deviceUUID, pdevice->device_uuid, VK_UUID_SIZE);
979 memcpy(id_props->driverUUID, pdevice->driver_uuid, VK_UUID_SIZE);
980 /* The LUID is for Windows. */
981 id_props->deviceLUIDValid = false;
982 break;
983 }
984 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
985 /* Do nothing, not even logging. This is a non-PCI device, so we will
986 * never provide this extension.
987 */
988 break;
989 default:
990 v3dv_debug_ignored_stype(ext->sType);
991 break;
992 }
993 }
994 }
995
996 /* We support exactly one queue family. */
997 static const VkQueueFamilyProperties
998 v3dv_queue_family_properties = {
999 .queueFlags = VK_QUEUE_GRAPHICS_BIT |
1000 VK_QUEUE_COMPUTE_BIT |
1001 VK_QUEUE_TRANSFER_BIT,
1002 .queueCount = 1,
1003 .timestampValidBits = 64,
1004 .minImageTransferGranularity = { 1, 1, 1 },
1005 };
1006
1007 void
v3dv_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,uint32_t * pCount,VkQueueFamilyProperties * pQueueFamilyProperties)1008 v3dv_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
1009 uint32_t *pCount,
1010 VkQueueFamilyProperties *pQueueFamilyProperties)
1011 {
1012 VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pCount);
1013
1014 vk_outarray_append(&out, p) {
1015 *p = v3dv_queue_family_properties;
1016 }
1017 }
1018
1019 void
v3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,uint32_t * pQueueFamilyPropertyCount,VkQueueFamilyProperties2 * pQueueFamilyProperties)1020 v3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
1021 uint32_t *pQueueFamilyPropertyCount,
1022 VkQueueFamilyProperties2 *pQueueFamilyProperties)
1023 {
1024 VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pQueueFamilyPropertyCount);
1025
1026 vk_outarray_append(&out, p) {
1027 p->queueFamilyProperties = v3dv_queue_family_properties;
1028
1029 vk_foreach_struct(s, p->pNext) {
1030 v3dv_debug_ignored_stype(s->sType);
1031 }
1032 }
1033 }
1034
1035 void
v3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties * pMemoryProperties)1036 v3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
1037 VkPhysicalDeviceMemoryProperties *pMemoryProperties)
1038 {
1039 V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice);
1040 *pMemoryProperties = device->memory;
1041 }
1042
1043 void
v3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties2 * pMemoryProperties)1044 v3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
1045 VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
1046 {
1047 v3dv_GetPhysicalDeviceMemoryProperties(physicalDevice,
1048 &pMemoryProperties->memoryProperties);
1049
1050 vk_foreach_struct(ext, pMemoryProperties->pNext) {
1051 switch (ext->sType) {
1052 default:
1053 v3dv_debug_ignored_stype(ext->sType);
1054 break;
1055 }
1056 }
1057 }
1058
1059 PFN_vkVoidFunction
v3dv_GetInstanceProcAddr(VkInstance _instance,const char * pName)1060 v3dv_GetInstanceProcAddr(VkInstance _instance,
1061 const char *pName)
1062 {
1063 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1064
1065 /* The Vulkan 1.0 spec for vkGetInstanceProcAddr has a table of exactly
1066 * when we have to return valid function pointers, NULL, or it's left
1067 * undefined. See the table for exact details.
1068 */
1069 if (pName == NULL)
1070 return NULL;
1071
1072 #define LOOKUP_V3DV_ENTRYPOINT(entrypoint) \
1073 if (strcmp(pName, "vk" #entrypoint) == 0) \
1074 return (PFN_vkVoidFunction)v3dv_##entrypoint
1075
1076 LOOKUP_V3DV_ENTRYPOINT(EnumerateInstanceExtensionProperties);
1077 LOOKUP_V3DV_ENTRYPOINT(CreateInstance);
1078
1079 #undef LOOKUP_V3DV_ENTRYPOINT
1080
1081 if (instance == NULL)
1082 return NULL;
1083
1084 int idx = v3dv_get_instance_entrypoint_index(pName);
1085 if (idx >= 0)
1086 return instance->dispatch.entrypoints[idx];
1087
1088 idx = v3dv_get_physical_device_entrypoint_index(pName);
1089 if (idx >= 0)
1090 return instance->physicalDevice.dispatch.entrypoints[idx];
1091
1092 idx = v3dv_get_device_entrypoint_index(pName);
1093 if (idx >= 0)
1094 return instance->device_dispatch.entrypoints[idx];
1095
1096 return NULL;
1097 }
1098
1099 /* With version 1+ of the loader interface the ICD should expose
1100 * vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps.
1101 */
1102 PUBLIC
1103 VKAPI_ATTR PFN_vkVoidFunction
1104 VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance,
1105 const char *pName);
1106
1107 PUBLIC
1108 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)1109 vk_icdGetInstanceProcAddr(VkInstance instance,
1110 const char* pName)
1111 {
1112 return v3dv_GetInstanceProcAddr(instance, pName);
1113 }
1114
1115 PFN_vkVoidFunction
v3dv_GetDeviceProcAddr(VkDevice _device,const char * pName)1116 v3dv_GetDeviceProcAddr(VkDevice _device,
1117 const char *pName)
1118 {
1119 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1120
1121 if (!device || !pName)
1122 return NULL;
1123
1124 int idx = v3dv_get_device_entrypoint_index(pName);
1125 if (idx < 0)
1126 return NULL;
1127
1128 return device->dispatch.entrypoints[idx];
1129 }
1130
1131 /* With version 4+ of the loader interface the ICD should expose
1132 * vk_icdGetPhysicalDeviceProcAddr()
1133 */
1134 PUBLIC
1135 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1136 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,
1137 const char* pName);
1138
1139 PFN_vkVoidFunction
vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,const char * pName)1140 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,
1141 const char* pName)
1142 {
1143 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1144
1145 if (!pName || !instance)
1146 return NULL;
1147
1148 int idx = v3dv_get_physical_device_entrypoint_index(pName);
1149 if (idx < 0)
1150 return NULL;
1151
1152 return instance->physicalDevice.dispatch.entrypoints[idx];
1153 }
1154
1155 VkResult
v3dv_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)1156 v3dv_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
1157 const char *pLayerName,
1158 uint32_t *pPropertyCount,
1159 VkExtensionProperties *pProperties)
1160 {
1161 /* We don't support any layers */
1162 if (pLayerName)
1163 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1164
1165 V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice);
1166 VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
1167
1168 for (int i = 0; i < V3DV_DEVICE_EXTENSION_COUNT; i++) {
1169 if (device->supported_extensions.extensions[i]) {
1170 vk_outarray_append(&out, prop) {
1171 *prop = v3dv_device_extensions[i];
1172 }
1173 }
1174 }
1175
1176 return vk_outarray_status(&out);
1177 }
1178
1179 VkResult
v3dv_EnumerateInstanceLayerProperties(uint32_t * pPropertyCount,VkLayerProperties * pProperties)1180 v3dv_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
1181 VkLayerProperties *pProperties)
1182 {
1183 if (pProperties == NULL) {
1184 *pPropertyCount = 0;
1185 return VK_SUCCESS;
1186 }
1187
1188 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1189 }
1190
1191 VkResult
v3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,uint32_t * pPropertyCount,VkLayerProperties * pProperties)1192 v3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
1193 uint32_t *pPropertyCount,
1194 VkLayerProperties *pProperties)
1195 {
1196 V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
1197
1198 if (pProperties == NULL) {
1199 *pPropertyCount = 0;
1200 return VK_SUCCESS;
1201 }
1202
1203 return vk_error(physical_device->instance, VK_ERROR_LAYER_NOT_PRESENT);
1204 }
1205
1206 static VkResult
queue_init(struct v3dv_device * device,struct v3dv_queue * queue)1207 queue_init(struct v3dv_device *device, struct v3dv_queue *queue)
1208 {
1209 queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
1210 queue->device = device;
1211 queue->flags = 0;
1212 queue->noop_job = NULL;
1213 list_inithead(&queue->submit_wait_list);
1214 pthread_mutex_init(&queue->mutex, NULL);
1215 return VK_SUCCESS;
1216 }
1217
1218 static void
queue_finish(struct v3dv_queue * queue)1219 queue_finish(struct v3dv_queue *queue)
1220 {
1221 assert(list_is_empty(&queue->submit_wait_list));
1222 if (queue->noop_job)
1223 v3dv_job_destroy(queue->noop_job);
1224 pthread_mutex_destroy(&queue->mutex);
1225 }
1226
1227 static void
init_device_dispatch(struct v3dv_device * device)1228 init_device_dispatch(struct v3dv_device *device)
1229 {
1230 for (unsigned i = 0; i < ARRAY_SIZE(device->dispatch.entrypoints); i++) {
1231 /* Vulkan requires that entrypoints for extensions which have not been
1232 * enabled must not be advertised.
1233 */
1234 if (!v3dv_device_entrypoint_is_enabled(i, device->instance->app_info.api_version,
1235 &device->instance->enabled_extensions,
1236 &device->enabled_extensions)) {
1237 device->dispatch.entrypoints[i] = NULL;
1238 } else {
1239 device->dispatch.entrypoints[i] =
1240 v3dv_device_dispatch_table.entrypoints[i];
1241 }
1242 }
1243 }
1244
1245 static void
init_device_meta(struct v3dv_device * device)1246 init_device_meta(struct v3dv_device *device)
1247 {
1248 mtx_init(&device->meta.mtx, mtx_plain);
1249 v3dv_meta_clear_init(device);
1250 v3dv_meta_blit_init(device);
1251 }
1252
1253 static void
destroy_device_meta(struct v3dv_device * device)1254 destroy_device_meta(struct v3dv_device *device)
1255 {
1256 mtx_destroy(&device->meta.mtx);
1257 v3dv_meta_clear_finish(device);
1258 v3dv_meta_blit_finish(device);
1259 }
1260
1261 VkResult
v3dv_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)1262 v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
1263 const VkDeviceCreateInfo *pCreateInfo,
1264 const VkAllocationCallbacks *pAllocator,
1265 VkDevice *pDevice)
1266 {
1267 V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
1268 struct v3dv_instance *instance = physical_device->instance;
1269 VkResult result;
1270 struct v3dv_device *device;
1271
1272 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
1273
1274 /* Check enabled extensions */
1275 struct v3dv_device_extension_table enabled_extensions = { };
1276 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
1277 int idx;
1278 for (idx = 0; idx < V3DV_DEVICE_EXTENSION_COUNT; idx++) {
1279 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
1280 v3dv_device_extensions[idx].extensionName) == 0)
1281 break;
1282 }
1283
1284 if (idx >= V3DV_DEVICE_EXTENSION_COUNT)
1285 return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT);
1286
1287 if (!physical_device->supported_extensions.extensions[idx])
1288 return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT);
1289
1290 enabled_extensions.extensions[idx] = true;
1291 }
1292
1293 /* Check enabled features */
1294 if (pCreateInfo->pEnabledFeatures) {
1295 VkPhysicalDeviceFeatures supported_features;
1296 v3dv_GetPhysicalDeviceFeatures(physicalDevice, &supported_features);
1297 VkBool32 *supported_feature = (VkBool32 *)&supported_features;
1298 VkBool32 *enabled_feature = (VkBool32 *)pCreateInfo->pEnabledFeatures;
1299 unsigned num_features = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
1300 for (uint32_t i = 0; i < num_features; i++) {
1301 if (enabled_feature[i] && !supported_feature[i])
1302 return vk_error(instance, VK_ERROR_FEATURE_NOT_PRESENT);
1303 }
1304 }
1305
1306 /* Check requested queues (we only expose one queue ) */
1307 assert(pCreateInfo->queueCreateInfoCount == 1);
1308 for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
1309 assert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex == 0);
1310 assert(pCreateInfo->pQueueCreateInfos[i].queueCount == 1);
1311 if (pCreateInfo->pQueueCreateInfos[i].flags != 0)
1312 return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
1313 }
1314
1315 device = vk_zalloc2(&physical_device->instance->alloc, pAllocator,
1316 sizeof(*device), 8,
1317 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1318 if (!device)
1319 return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1320
1321 device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
1322 device->instance = instance;
1323
1324 if (pAllocator)
1325 device->alloc = *pAllocator;
1326 else
1327 device->alloc = physical_device->instance->alloc;
1328
1329 device->render_fd = physical_device->render_fd;
1330 if (device->render_fd == -1) {
1331 result = VK_ERROR_INITIALIZATION_FAILED;
1332 goto fail;
1333 }
1334
1335 if (physical_device->display_fd != -1) {
1336 device->display_fd = physical_device->display_fd;
1337 if (device->display_fd == -1) {
1338 result = VK_ERROR_INITIALIZATION_FAILED;
1339 goto fail;
1340 }
1341 } else {
1342 device->display_fd = -1;
1343 }
1344
1345 pthread_mutex_init(&device->mutex, NULL);
1346
1347 result = queue_init(device, &device->queue);
1348 if (result != VK_SUCCESS)
1349 goto fail;
1350
1351 device->devinfo = physical_device->devinfo;
1352 device->enabled_extensions = enabled_extensions;
1353
1354 if (pCreateInfo->pEnabledFeatures) {
1355 memcpy(&device->features, pCreateInfo->pEnabledFeatures,
1356 sizeof(device->features));
1357 }
1358
1359 int ret = drmSyncobjCreate(device->render_fd,
1360 DRM_SYNCOBJ_CREATE_SIGNALED,
1361 &device->last_job_sync);
1362 if (ret) {
1363 result = VK_ERROR_INITIALIZATION_FAILED;
1364 goto fail;
1365 }
1366
1367 init_device_dispatch(device);
1368 init_device_meta(device);
1369 v3dv_bo_cache_init(device);
1370 v3dv_pipeline_cache_init(&device->default_pipeline_cache, device,
1371 device->instance->default_pipeline_cache_enabled);
1372
1373 *pDevice = v3dv_device_to_handle(device);
1374
1375 return VK_SUCCESS;
1376
1377 fail:
1378 vk_free(&device->alloc, device);
1379
1380 return result;
1381 }
1382
1383 void
v3dv_DestroyDevice(VkDevice _device,const VkAllocationCallbacks * pAllocator)1384 v3dv_DestroyDevice(VkDevice _device,
1385 const VkAllocationCallbacks *pAllocator)
1386 {
1387 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1388
1389 v3dv_DeviceWaitIdle(_device);
1390 queue_finish(&device->queue);
1391 pthread_mutex_destroy(&device->mutex);
1392 drmSyncobjDestroy(device->render_fd, device->last_job_sync);
1393 destroy_device_meta(device);
1394 v3dv_pipeline_cache_finish(&device->default_pipeline_cache);
1395
1396 /* Bo cache should be removed the last, as any other object could be
1397 * freeing their private bos
1398 */
1399 v3dv_bo_cache_destroy(device);
1400
1401 vk_free2(&default_alloc, pAllocator, device);
1402 }
1403
1404 void
v3dv_GetDeviceQueue(VkDevice _device,uint32_t queueFamilyIndex,uint32_t queueIndex,VkQueue * pQueue)1405 v3dv_GetDeviceQueue(VkDevice _device,
1406 uint32_t queueFamilyIndex,
1407 uint32_t queueIndex,
1408 VkQueue *pQueue)
1409 {
1410 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1411
1412 assert(queueIndex == 0);
1413 assert(queueFamilyIndex == 0);
1414
1415 *pQueue = v3dv_queue_to_handle(&device->queue);
1416 }
1417
1418 VkResult
v3dv_DeviceWaitIdle(VkDevice _device)1419 v3dv_DeviceWaitIdle(VkDevice _device)
1420 {
1421 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1422 return v3dv_QueueWaitIdle(v3dv_queue_to_handle(&device->queue));
1423 }
1424
1425 VkResult
v3dv_CreateDebugReportCallbackEXT(VkInstance _instance,const VkDebugReportCallbackCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDebugReportCallbackEXT * pCallback)1426 v3dv_CreateDebugReportCallbackEXT(VkInstance _instance,
1427 const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
1428 const VkAllocationCallbacks* pAllocator,
1429 VkDebugReportCallbackEXT* pCallback)
1430 {
1431 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1432 return vk_create_debug_report_callback(&instance->debug_report_callbacks,
1433 pCreateInfo, pAllocator, &instance->alloc,
1434 pCallback);
1435 }
1436
1437 void
v3dv_DestroyDebugReportCallbackEXT(VkInstance _instance,VkDebugReportCallbackEXT _callback,const VkAllocationCallbacks * pAllocator)1438 v3dv_DestroyDebugReportCallbackEXT(VkInstance _instance,
1439 VkDebugReportCallbackEXT _callback,
1440 const VkAllocationCallbacks* pAllocator)
1441 {
1442 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1443 vk_destroy_debug_report_callback(&instance->debug_report_callbacks,
1444 _callback, pAllocator, &instance->alloc);
1445 }
1446
1447 static VkResult
device_alloc(struct v3dv_device * device,struct v3dv_device_memory * mem,VkDeviceSize size)1448 device_alloc(struct v3dv_device *device,
1449 struct v3dv_device_memory *mem,
1450 VkDeviceSize size)
1451 {
1452 /* Our kernel interface is 32-bit */
1453 if (size > UINT32_MAX)
1454 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1455
1456 mem->bo = v3dv_bo_alloc(device, size, "device_alloc", false);
1457 if (!mem->bo)
1458 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1459
1460 return VK_SUCCESS;
1461 }
1462
1463 static void
device_free_wsi_dumb(int32_t display_fd,int32_t dumb_handle)1464 device_free_wsi_dumb(int32_t display_fd, int32_t dumb_handle)
1465 {
1466 assert(display_fd != -1);
1467 if (dumb_handle < 0)
1468 return;
1469
1470 struct drm_mode_destroy_dumb destroy_dumb = {
1471 .handle = dumb_handle,
1472 };
1473 v3dv_ioctl(display_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
1474 }
1475
1476 static void
device_free(struct v3dv_device * device,struct v3dv_device_memory * mem)1477 device_free(struct v3dv_device *device, struct v3dv_device_memory *mem)
1478 {
1479 /* If this memory allocation was for WSI, then we need to use the
1480 * display device to free the allocated dumb BO.
1481 */
1482 if (mem->is_for_wsi) {
1483 assert(mem->has_bo_ownership);
1484 device_free_wsi_dumb(device->instance->physicalDevice.display_fd,
1485 mem->bo->dumb_handle);
1486 }
1487
1488 if (mem->has_bo_ownership)
1489 v3dv_bo_free(device, mem->bo);
1490 else if (mem->bo)
1491 vk_free(&device->alloc, mem->bo);
1492 }
1493
1494 static void
device_unmap(struct v3dv_device * device,struct v3dv_device_memory * mem)1495 device_unmap(struct v3dv_device *device, struct v3dv_device_memory *mem)
1496 {
1497 assert(mem && mem->bo->map && mem->bo->map_size > 0);
1498 v3dv_bo_unmap(device, mem->bo);
1499 }
1500
1501 static VkResult
device_map(struct v3dv_device * device,struct v3dv_device_memory * mem)1502 device_map(struct v3dv_device *device, struct v3dv_device_memory *mem)
1503 {
1504 assert(mem && mem->bo);
1505
1506 /* From the spec:
1507 *
1508 * "After a successful call to vkMapMemory the memory object memory is
1509 * considered to be currently host mapped. It is an application error to
1510 * call vkMapMemory on a memory object that is already host mapped."
1511 *
1512 * We are not concerned with this ourselves (validation layers should
1513 * catch these errors and warn users), however, the driver may internally
1514 * map things (for example for debug CLIF dumps or some CPU-side operations)
1515 * so by the time the user calls here the buffer might already been mapped
1516 * internally by the driver.
1517 */
1518 if (mem->bo->map) {
1519 assert(mem->bo->map_size == mem->bo->size);
1520 return VK_SUCCESS;
1521 }
1522
1523 bool ok = v3dv_bo_map(device, mem->bo, mem->bo->size);
1524 if (!ok)
1525 return VK_ERROR_MEMORY_MAP_FAILED;
1526
1527 return VK_SUCCESS;
1528 }
1529
1530 static VkResult
device_import_bo(struct v3dv_device * device,const VkAllocationCallbacks * pAllocator,int fd,uint64_t size,struct v3dv_bo ** bo)1531 device_import_bo(struct v3dv_device *device,
1532 const VkAllocationCallbacks *pAllocator,
1533 int fd, uint64_t size,
1534 struct v3dv_bo **bo)
1535 {
1536 VkResult result;
1537
1538 *bo = vk_alloc2(&device->alloc, pAllocator, sizeof(struct v3dv_bo), 8,
1539 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1540 if (*bo == NULL) {
1541 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1542 goto fail;
1543 }
1544
1545 off_t real_size = lseek(fd, 0, SEEK_END);
1546 lseek(fd, 0, SEEK_SET);
1547 if (real_size < 0 || (uint64_t) real_size < size) {
1548 result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
1549 goto fail;
1550 }
1551
1552 int ret;
1553 uint32_t handle;
1554 ret = drmPrimeFDToHandle(device->render_fd, fd, &handle);
1555 if (ret) {
1556 result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
1557 goto fail;
1558 }
1559
1560 struct drm_v3d_get_bo_offset get_offset = {
1561 .handle = handle,
1562 };
1563 ret = v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_BO_OFFSET, &get_offset);
1564 if (ret) {
1565 result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
1566 goto fail;
1567 }
1568 assert(get_offset.offset != 0);
1569
1570 v3dv_bo_init(*bo, handle, size, get_offset.offset, "import", false);
1571
1572 return VK_SUCCESS;
1573
1574 fail:
1575 if (*bo) {
1576 vk_free2(&device->alloc, pAllocator, *bo);
1577 *bo = NULL;
1578 }
1579 return result;
1580 }
1581
1582 static VkResult
device_alloc_for_wsi(struct v3dv_device * device,const VkAllocationCallbacks * pAllocator,struct v3dv_device_memory * mem,VkDeviceSize size)1583 device_alloc_for_wsi(struct v3dv_device *device,
1584 const VkAllocationCallbacks *pAllocator,
1585 struct v3dv_device_memory *mem,
1586 VkDeviceSize size)
1587 {
1588 /* In the simulator we can get away with a regular allocation since both
1589 * allocation and rendering happen in the same DRM render node. On actual
1590 * hardware we need to allocate our winsys BOs on the vc4 display device
1591 * and import them into v3d.
1592 */
1593 #if using_v3d_simulator
1594 return device_alloc(device, mem, size);
1595 #else
1596 mem->is_for_wsi = true;
1597
1598 assert(device->display_fd != -1);
1599 int display_fd = device->instance->physicalDevice.display_fd;
1600 struct drm_mode_create_dumb create_dumb = {
1601 .width = 1024, /* one page */
1602 .height = align(size, 4096) / 4096,
1603 .bpp = util_format_get_blocksizebits(PIPE_FORMAT_RGBA8888_UNORM),
1604 };
1605
1606 int err;
1607 err = v3dv_ioctl(display_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
1608 if (err < 0)
1609 goto fail_create;
1610
1611 int fd;
1612 err =
1613 drmPrimeHandleToFD(display_fd, create_dumb.handle, O_CLOEXEC, &fd);
1614 if (err < 0)
1615 goto fail_export;
1616
1617 VkResult result = device_import_bo(device, pAllocator, fd, size, &mem->bo);
1618 close(fd);
1619 if (result != VK_SUCCESS)
1620 goto fail_import;
1621
1622 mem->bo->dumb_handle = create_dumb.handle;
1623 return VK_SUCCESS;
1624
1625 fail_import:
1626 fail_export:
1627 device_free_wsi_dumb(display_fd, create_dumb.handle);
1628
1629 fail_create:
1630 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1631 #endif
1632 }
1633
1634 VkResult
v3dv_AllocateMemory(VkDevice _device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * pMem)1635 v3dv_AllocateMemory(VkDevice _device,
1636 const VkMemoryAllocateInfo *pAllocateInfo,
1637 const VkAllocationCallbacks *pAllocator,
1638 VkDeviceMemory *pMem)
1639 {
1640 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1641 struct v3dv_device_memory *mem;
1642 struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
1643
1644 assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
1645
1646 /* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
1647 assert(pAllocateInfo->allocationSize > 0);
1648
1649 mem = vk_alloc2(&device->alloc, pAllocator, sizeof(*mem), 8,
1650 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1651 if (mem == NULL)
1652 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
1653
1654 assert(pAllocateInfo->memoryTypeIndex < pdevice->memory.memoryTypeCount);
1655 mem->type = &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex];
1656 mem->has_bo_ownership = true;
1657 mem->is_for_wsi = false;
1658
1659 const struct wsi_memory_allocate_info *wsi_info = NULL;
1660 const VkImportMemoryFdInfoKHR *fd_info = NULL;
1661 vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
1662 switch ((unsigned)ext->sType) {
1663 case VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA:
1664 wsi_info = (void *)ext;
1665 break;
1666 case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
1667 fd_info = (void *)ext;
1668 break;
1669 default:
1670 v3dv_debug_ignored_stype(ext->sType);
1671 break;
1672 }
1673 }
1674
1675 VkResult result = VK_SUCCESS;
1676 if (wsi_info) {
1677 result = device_alloc_for_wsi(device, pAllocator, mem,
1678 pAllocateInfo->allocationSize);
1679 } else if (fd_info && fd_info->handleType) {
1680 assert(fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
1681 fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
1682 result = device_import_bo(device, pAllocator,
1683 fd_info->fd, pAllocateInfo->allocationSize,
1684 &mem->bo);
1685 mem->has_bo_ownership = false;
1686 if (result == VK_SUCCESS)
1687 close(fd_info->fd);
1688 } else {
1689 result = device_alloc(device, mem, pAllocateInfo->allocationSize);
1690 }
1691
1692 if (result != VK_SUCCESS) {
1693 vk_free2(&device->alloc, pAllocator, mem);
1694 return vk_error(device->instance, result);
1695 }
1696
1697 *pMem = v3dv_device_memory_to_handle(mem);
1698 return result;
1699 }
1700
1701 void
v3dv_FreeMemory(VkDevice _device,VkDeviceMemory _mem,const VkAllocationCallbacks * pAllocator)1702 v3dv_FreeMemory(VkDevice _device,
1703 VkDeviceMemory _mem,
1704 const VkAllocationCallbacks *pAllocator)
1705 {
1706 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1707 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _mem);
1708
1709 if (mem == NULL)
1710 return;
1711
1712 if (mem->bo->map)
1713 v3dv_UnmapMemory(_device, _mem);
1714
1715 device_free(device, mem);
1716
1717 vk_free2(&device->alloc, pAllocator, mem);
1718 }
1719
1720 VkResult
v3dv_MapMemory(VkDevice _device,VkDeviceMemory _memory,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags,void ** ppData)1721 v3dv_MapMemory(VkDevice _device,
1722 VkDeviceMemory _memory,
1723 VkDeviceSize offset,
1724 VkDeviceSize size,
1725 VkMemoryMapFlags flags,
1726 void **ppData)
1727 {
1728 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1729 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1730
1731 if (mem == NULL) {
1732 *ppData = NULL;
1733 return VK_SUCCESS;
1734 }
1735
1736 assert(offset < mem->bo->size);
1737
1738 /* Since the driver can map BOs internally as well and the mapped range
1739 * required by the user or the driver might not be the same, we always map
1740 * the entire BO and then add the requested offset to the start address
1741 * of the mapped region.
1742 */
1743 VkResult result = device_map(device, mem);
1744 if (result != VK_SUCCESS)
1745 return vk_error(device->instance, result);
1746
1747 *ppData = ((uint8_t *) mem->bo->map) + offset;
1748 return VK_SUCCESS;
1749 }
1750
1751 void
v3dv_UnmapMemory(VkDevice _device,VkDeviceMemory _memory)1752 v3dv_UnmapMemory(VkDevice _device,
1753 VkDeviceMemory _memory)
1754 {
1755 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1756 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1757
1758 if (mem == NULL)
1759 return;
1760
1761 device_unmap(device, mem);
1762 }
1763
1764 VkResult
v3dv_FlushMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)1765 v3dv_FlushMappedMemoryRanges(VkDevice _device,
1766 uint32_t memoryRangeCount,
1767 const VkMappedMemoryRange *pMemoryRanges)
1768 {
1769 return VK_SUCCESS;
1770 }
1771
1772 VkResult
v3dv_InvalidateMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)1773 v3dv_InvalidateMappedMemoryRanges(VkDevice _device,
1774 uint32_t memoryRangeCount,
1775 const VkMappedMemoryRange *pMemoryRanges)
1776 {
1777 return VK_SUCCESS;
1778 }
1779
1780 void
v3dv_GetImageMemoryRequirements(VkDevice _device,VkImage _image,VkMemoryRequirements * pMemoryRequirements)1781 v3dv_GetImageMemoryRequirements(VkDevice _device,
1782 VkImage _image,
1783 VkMemoryRequirements *pMemoryRequirements)
1784 {
1785 V3DV_FROM_HANDLE(v3dv_image, image, _image);
1786
1787 assert(image->size > 0);
1788
1789 pMemoryRequirements->size = image->size;
1790 pMemoryRequirements->alignment = image->alignment;
1791 pMemoryRequirements->memoryTypeBits = 0x1;
1792 }
1793
1794 VkResult
v3dv_BindImageMemory(VkDevice _device,VkImage _image,VkDeviceMemory _memory,VkDeviceSize memoryOffset)1795 v3dv_BindImageMemory(VkDevice _device,
1796 VkImage _image,
1797 VkDeviceMemory _memory,
1798 VkDeviceSize memoryOffset)
1799 {
1800 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1801 V3DV_FROM_HANDLE(v3dv_image, image, _image);
1802
1803 /* Valid usage:
1804 *
1805 * "memoryOffset must be an integer multiple of the alignment member of
1806 * the VkMemoryRequirements structure returned from a call to
1807 * vkGetImageMemoryRequirements with image"
1808 */
1809 assert(memoryOffset % image->alignment == 0);
1810 assert(memoryOffset < mem->bo->size);
1811
1812 image->mem = mem;
1813 image->mem_offset = memoryOffset;
1814
1815 return VK_SUCCESS;
1816 }
1817
1818 void
v3dv_GetBufferMemoryRequirements(VkDevice _device,VkBuffer _buffer,VkMemoryRequirements * pMemoryRequirements)1819 v3dv_GetBufferMemoryRequirements(VkDevice _device,
1820 VkBuffer _buffer,
1821 VkMemoryRequirements* pMemoryRequirements)
1822 {
1823 V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
1824
1825 pMemoryRequirements->memoryTypeBits = 0x1;
1826 pMemoryRequirements->alignment = buffer->alignment;
1827 pMemoryRequirements->size =
1828 align64(buffer->size, pMemoryRequirements->alignment);
1829 }
1830
1831 VkResult
v3dv_BindBufferMemory(VkDevice _device,VkBuffer _buffer,VkDeviceMemory _memory,VkDeviceSize memoryOffset)1832 v3dv_BindBufferMemory(VkDevice _device,
1833 VkBuffer _buffer,
1834 VkDeviceMemory _memory,
1835 VkDeviceSize memoryOffset)
1836 {
1837 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
1838 V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
1839
1840 /* Valid usage:
1841 *
1842 * "memoryOffset must be an integer multiple of the alignment member of
1843 * the VkMemoryRequirements structure returned from a call to
1844 * vkGetBufferMemoryRequirements with buffer"
1845 */
1846 assert(memoryOffset % buffer->alignment == 0);
1847 assert(memoryOffset < mem->bo->size);
1848
1849 buffer->mem = mem;
1850 buffer->mem_offset = memoryOffset;
1851
1852 return VK_SUCCESS;
1853 }
1854
1855 VkResult
v3dv_CreateBuffer(VkDevice _device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer)1856 v3dv_CreateBuffer(VkDevice _device,
1857 const VkBufferCreateInfo *pCreateInfo,
1858 const VkAllocationCallbacks *pAllocator,
1859 VkBuffer *pBuffer)
1860 {
1861 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1862 struct v3dv_buffer *buffer;
1863
1864 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
1865 assert(pCreateInfo->usage != 0);
1866
1867 /* We don't support any flags for now */
1868 assert(pCreateInfo->flags == 0);
1869
1870 buffer = vk_alloc2(&device->alloc, pAllocator, sizeof(*buffer), 8,
1871 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1872 if (buffer == NULL)
1873 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1874
1875 buffer->size = pCreateInfo->size;
1876 buffer->usage = pCreateInfo->usage;
1877 buffer->alignment = 256; /* nonCoherentAtomSize */
1878
1879 /* Limit allocations to 32-bit */
1880 const VkDeviceSize aligned_size = align64(buffer->size, buffer->alignment);
1881 if (aligned_size > UINT32_MAX || aligned_size < buffer->size)
1882 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
1883
1884 *pBuffer = v3dv_buffer_to_handle(buffer);
1885
1886 return VK_SUCCESS;
1887 }
1888
1889 void
v3dv_DestroyBuffer(VkDevice _device,VkBuffer _buffer,const VkAllocationCallbacks * pAllocator)1890 v3dv_DestroyBuffer(VkDevice _device,
1891 VkBuffer _buffer,
1892 const VkAllocationCallbacks *pAllocator)
1893 {
1894 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1895 V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
1896
1897 if (!buffer)
1898 return;
1899
1900 vk_free2(&device->alloc, pAllocator, buffer);
1901 }
1902
1903 /**
1904 * This computes the maximum bpp used by any of the render targets used by
1905 * a particular subpass and checks if any of those render targets are
1906 * multisampled. If we don't have a subpass (when we are not inside a
1907 * render pass), then we assume that all framebuffer attachments are used.
1908 */
1909 void
v3dv_framebuffer_compute_internal_bpp_msaa(const struct v3dv_framebuffer * framebuffer,const struct v3dv_subpass * subpass,uint8_t * max_bpp,bool * msaa)1910 v3dv_framebuffer_compute_internal_bpp_msaa(
1911 const struct v3dv_framebuffer *framebuffer,
1912 const struct v3dv_subpass *subpass,
1913 uint8_t *max_bpp,
1914 bool *msaa)
1915 {
1916 STATIC_ASSERT(RENDER_TARGET_MAXIMUM_32BPP == 0);
1917 *max_bpp = RENDER_TARGET_MAXIMUM_32BPP;
1918 *msaa = false;
1919
1920 if (subpass) {
1921 for (uint32_t i = 0; i < subpass->color_count; i++) {
1922 uint32_t att_idx = subpass->color_attachments[i].attachment;
1923 if (att_idx == VK_ATTACHMENT_UNUSED)
1924 continue;
1925
1926 const struct v3dv_image_view *att = framebuffer->attachments[att_idx];
1927 assert(att);
1928
1929 if (att->aspects & VK_IMAGE_ASPECT_COLOR_BIT)
1930 *max_bpp = MAX2(*max_bpp, att->internal_bpp);
1931
1932 if (att->image->samples > VK_SAMPLE_COUNT_1_BIT)
1933 *msaa = true;
1934 }
1935
1936 if (!*msaa && subpass->ds_attachment.attachment != VK_ATTACHMENT_UNUSED) {
1937 const struct v3dv_image_view *att =
1938 framebuffer->attachments[subpass->ds_attachment.attachment];
1939 assert(att);
1940
1941 if (att->image->samples > VK_SAMPLE_COUNT_1_BIT)
1942 *msaa = true;
1943 }
1944
1945 return;
1946 }
1947
1948 assert(framebuffer->attachment_count <= 4);
1949 for (uint32_t i = 0; i < framebuffer->attachment_count; i++) {
1950 const struct v3dv_image_view *att = framebuffer->attachments[i];
1951 assert(att);
1952
1953 if (att->aspects & VK_IMAGE_ASPECT_COLOR_BIT)
1954 *max_bpp = MAX2(*max_bpp, att->internal_bpp);
1955
1956 if (att->image->samples > VK_SAMPLE_COUNT_1_BIT)
1957 *msaa = true;
1958 }
1959
1960 return;
1961 }
1962
1963 VkResult
v3dv_CreateFramebuffer(VkDevice _device,const VkFramebufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkFramebuffer * pFramebuffer)1964 v3dv_CreateFramebuffer(VkDevice _device,
1965 const VkFramebufferCreateInfo *pCreateInfo,
1966 const VkAllocationCallbacks *pAllocator,
1967 VkFramebuffer *pFramebuffer)
1968 {
1969 V3DV_FROM_HANDLE(v3dv_device, device, _device);
1970 struct v3dv_framebuffer *framebuffer;
1971
1972 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);
1973
1974 size_t size = sizeof(*framebuffer) +
1975 sizeof(struct v3dv_image_view *) * pCreateInfo->attachmentCount;
1976 framebuffer = vk_alloc2(&device->alloc, pAllocator, size, 8,
1977 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1978 if (framebuffer == NULL)
1979 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1980
1981 framebuffer->width = pCreateInfo->width;
1982 framebuffer->height = pCreateInfo->height;
1983 framebuffer->layers = pCreateInfo->layers;
1984 framebuffer->has_edge_padding = true;
1985
1986 framebuffer->attachment_count = pCreateInfo->attachmentCount;
1987 framebuffer->color_attachment_count = 0;
1988 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
1989 framebuffer->attachments[i] =
1990 v3dv_image_view_from_handle(pCreateInfo->pAttachments[i]);
1991 if (framebuffer->attachments[i]->aspects & VK_IMAGE_ASPECT_COLOR_BIT)
1992 framebuffer->color_attachment_count++;
1993 }
1994
1995 *pFramebuffer = v3dv_framebuffer_to_handle(framebuffer);
1996
1997 return VK_SUCCESS;
1998 }
1999
2000 void
v3dv_DestroyFramebuffer(VkDevice _device,VkFramebuffer _fb,const VkAllocationCallbacks * pAllocator)2001 v3dv_DestroyFramebuffer(VkDevice _device,
2002 VkFramebuffer _fb,
2003 const VkAllocationCallbacks *pAllocator)
2004 {
2005 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2006 V3DV_FROM_HANDLE(v3dv_framebuffer, fb, _fb);
2007
2008 if (!fb)
2009 return;
2010
2011 vk_free2(&device->alloc, pAllocator, fb);
2012 }
2013
2014 VkResult
v3dv_GetMemoryFdPropertiesKHR(VkDevice _device,VkExternalMemoryHandleTypeFlagBits handleType,int fd,VkMemoryFdPropertiesKHR * pMemoryFdProperties)2015 v3dv_GetMemoryFdPropertiesKHR(VkDevice _device,
2016 VkExternalMemoryHandleTypeFlagBits handleType,
2017 int fd,
2018 VkMemoryFdPropertiesKHR *pMemoryFdProperties)
2019 {
2020 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2021 struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
2022
2023 switch (handleType) {
2024 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
2025 pMemoryFdProperties->memoryTypeBits =
2026 (1 << pdevice->memory.memoryTypeCount) - 1;
2027 return VK_SUCCESS;
2028 default:
2029 return vk_error(device->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
2030 }
2031 }
2032
2033 VkResult
v3dv_GetMemoryFdKHR(VkDevice _device,const VkMemoryGetFdInfoKHR * pGetFdInfo,int * pFd)2034 v3dv_GetMemoryFdKHR(VkDevice _device,
2035 const VkMemoryGetFdInfoKHR *pGetFdInfo,
2036 int *pFd)
2037 {
2038 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2039 V3DV_FROM_HANDLE(v3dv_device_memory, mem, pGetFdInfo->memory);
2040
2041 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR);
2042 assert(pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
2043 pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2044
2045 int fd, ret;
2046 ret =
2047 drmPrimeHandleToFD(device->render_fd, mem->bo->handle, DRM_CLOEXEC, &fd);
2048 if (ret)
2049 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2050
2051 *pFd = fd;
2052
2053 return VK_SUCCESS;
2054 }
2055
2056 VkResult
v3dv_CreateEvent(VkDevice _device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * pEvent)2057 v3dv_CreateEvent(VkDevice _device,
2058 const VkEventCreateInfo *pCreateInfo,
2059 const VkAllocationCallbacks *pAllocator,
2060 VkEvent *pEvent)
2061 {
2062 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2063 struct v3dv_event *event =
2064 vk_alloc2(&device->alloc, pAllocator, sizeof(*event), 8,
2065 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2066 if (!event)
2067 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2068
2069 /* Events are created in the unsignaled state */
2070 event->state = false;
2071 *pEvent = v3dv_event_to_handle(event);
2072
2073 return VK_SUCCESS;
2074 }
2075
2076 void
v3dv_DestroyEvent(VkDevice _device,VkEvent _event,const VkAllocationCallbacks * pAllocator)2077 v3dv_DestroyEvent(VkDevice _device,
2078 VkEvent _event,
2079 const VkAllocationCallbacks *pAllocator)
2080 {
2081 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2082 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2083
2084 if (!event)
2085 return;
2086
2087 vk_free2(&device->alloc, pAllocator, event);
2088 }
2089
2090 VkResult
v3dv_GetEventStatus(VkDevice _device,VkEvent _event)2091 v3dv_GetEventStatus(VkDevice _device, VkEvent _event)
2092 {
2093 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2094 return p_atomic_read(&event->state) ? VK_EVENT_SET : VK_EVENT_RESET;
2095 }
2096
2097 VkResult
v3dv_SetEvent(VkDevice _device,VkEvent _event)2098 v3dv_SetEvent(VkDevice _device, VkEvent _event)
2099 {
2100 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2101 p_atomic_set(&event->state, 1);
2102 return VK_SUCCESS;
2103 }
2104
2105 VkResult
v3dv_ResetEvent(VkDevice _device,VkEvent _event)2106 v3dv_ResetEvent(VkDevice _device, VkEvent _event)
2107 {
2108 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2109 p_atomic_set(&event->state, 0);
2110 return VK_SUCCESS;
2111 }
2112
2113 static const enum V3DX(Wrap_Mode) vk_to_v3d_wrap_mode[] = {
2114 [VK_SAMPLER_ADDRESS_MODE_REPEAT] = V3D_WRAP_MODE_REPEAT,
2115 [VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT] = V3D_WRAP_MODE_MIRROR,
2116 [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE] = V3D_WRAP_MODE_CLAMP,
2117 [VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE] = V3D_WRAP_MODE_MIRROR_ONCE,
2118 [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER] = V3D_WRAP_MODE_BORDER,
2119 };
2120
2121 static const enum V3DX(Compare_Function)
2122 vk_to_v3d_compare_func[] = {
2123 [VK_COMPARE_OP_NEVER] = V3D_COMPARE_FUNC_NEVER,
2124 [VK_COMPARE_OP_LESS] = V3D_COMPARE_FUNC_LESS,
2125 [VK_COMPARE_OP_EQUAL] = V3D_COMPARE_FUNC_EQUAL,
2126 [VK_COMPARE_OP_LESS_OR_EQUAL] = V3D_COMPARE_FUNC_LEQUAL,
2127 [VK_COMPARE_OP_GREATER] = V3D_COMPARE_FUNC_GREATER,
2128 [VK_COMPARE_OP_NOT_EQUAL] = V3D_COMPARE_FUNC_NOTEQUAL,
2129 [VK_COMPARE_OP_GREATER_OR_EQUAL] = V3D_COMPARE_FUNC_GEQUAL,
2130 [VK_COMPARE_OP_ALWAYS] = V3D_COMPARE_FUNC_ALWAYS,
2131 };
2132
2133 static void
pack_sampler_state(struct v3dv_sampler * sampler,const VkSamplerCreateInfo * pCreateInfo)2134 pack_sampler_state(struct v3dv_sampler *sampler,
2135 const VkSamplerCreateInfo *pCreateInfo)
2136 {
2137 enum V3DX(Border_Color_Mode) border_color_mode;
2138
2139 /* For now we only support the preset Vulkan border color modes. If we
2140 * want to implement VK_EXT_custom_border_color in the future we would have
2141 * to use V3D_BORDER_COLOR_FOLLOWS, and fill up border_color_word_[0/1/2/3]
2142 * SAMPLER_STATE.
2143 */
2144 switch (pCreateInfo->borderColor) {
2145 case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
2146 case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
2147 border_color_mode = V3D_BORDER_COLOR_0000;
2148 break;
2149 case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
2150 case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
2151 border_color_mode = V3D_BORDER_COLOR_0001;
2152 break;
2153 case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
2154 case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
2155 border_color_mode = V3D_BORDER_COLOR_1111;
2156 break;
2157 default:
2158 unreachable("Unknown border color");
2159 break;
2160 }
2161
2162 /* For some texture formats, when clamping to transparent black border the
2163 * CTS expects alpha to be set to 1 instead of 0, but the border color mode
2164 * will take priority over the texture state swizzle, so the only way to
2165 * fix that is to apply a swizzle in the shader. Here we keep track of
2166 * whether we are activating that mode and we will decide if we need to
2167 * activate the texture swizzle lowering in the shader key at compile time
2168 * depending on the actual texture format.
2169 */
2170 if ((pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
2171 pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
2172 pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) &&
2173 border_color_mode == V3D_BORDER_COLOR_0000) {
2174 sampler->clamp_to_transparent_black_border = true;
2175 }
2176
2177 v3dv_pack(sampler->sampler_state, SAMPLER_STATE, s) {
2178 if (pCreateInfo->anisotropyEnable) {
2179 s.anisotropy_enable = true;
2180 if (pCreateInfo->maxAnisotropy > 8)
2181 s.maximum_anisotropy = 3;
2182 else if (pCreateInfo->maxAnisotropy > 4)
2183 s.maximum_anisotropy = 2;
2184 else if (pCreateInfo->maxAnisotropy > 2)
2185 s.maximum_anisotropy = 1;
2186 }
2187
2188 s.border_color_mode = border_color_mode;
2189
2190 s.wrap_i_border = false; /* Also hardcoded on v3d */
2191 s.wrap_s = vk_to_v3d_wrap_mode[pCreateInfo->addressModeU];
2192 s.wrap_t = vk_to_v3d_wrap_mode[pCreateInfo->addressModeV];
2193 s.wrap_r = vk_to_v3d_wrap_mode[pCreateInfo->addressModeW];
2194 s.fixed_bias = pCreateInfo->mipLodBias;
2195 s.max_level_of_detail = MIN2(MAX2(0, pCreateInfo->maxLod), 15);
2196 s.min_level_of_detail = MIN2(MAX2(0, pCreateInfo->minLod), 15);
2197 s.srgb_disable = 0; /* Not even set by v3d */
2198 s.depth_compare_function =
2199 vk_to_v3d_compare_func[pCreateInfo->compareEnable ?
2200 pCreateInfo->compareOp : VK_COMPARE_OP_NEVER];
2201 s.mip_filter_nearest = pCreateInfo->mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST;
2202 s.min_filter_nearest = pCreateInfo->minFilter == VK_FILTER_NEAREST;
2203 s.mag_filter_nearest = pCreateInfo->magFilter == VK_FILTER_NEAREST;
2204 }
2205 }
2206
2207 VkResult
v3dv_CreateSampler(VkDevice _device,const VkSamplerCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSampler * pSampler)2208 v3dv_CreateSampler(VkDevice _device,
2209 const VkSamplerCreateInfo *pCreateInfo,
2210 const VkAllocationCallbacks *pAllocator,
2211 VkSampler *pSampler)
2212 {
2213 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2214 struct v3dv_sampler *sampler;
2215
2216 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
2217
2218 sampler = vk_zalloc2(&device->alloc, pAllocator, sizeof(*sampler), 8,
2219 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2220 if (!sampler)
2221 return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2222
2223 sampler->compare_enable = pCreateInfo->compareEnable;
2224 sampler->unnormalized_coordinates = pCreateInfo->unnormalizedCoordinates;
2225 pack_sampler_state(sampler, pCreateInfo);
2226
2227 *pSampler = v3dv_sampler_to_handle(sampler);
2228
2229 return VK_SUCCESS;
2230 }
2231
2232 void
v3dv_DestroySampler(VkDevice _device,VkSampler _sampler,const VkAllocationCallbacks * pAllocator)2233 v3dv_DestroySampler(VkDevice _device,
2234 VkSampler _sampler,
2235 const VkAllocationCallbacks *pAllocator)
2236 {
2237 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2238 V3DV_FROM_HANDLE(v3dv_sampler, sampler, _sampler);
2239
2240 if (!sampler)
2241 return;
2242
2243 vk_free2(&device->alloc, pAllocator, sampler);
2244 }
2245
2246 void
v3dv_GetDeviceMemoryCommitment(VkDevice device,VkDeviceMemory memory,VkDeviceSize * pCommittedMemoryInBytes)2247 v3dv_GetDeviceMemoryCommitment(VkDevice device,
2248 VkDeviceMemory memory,
2249 VkDeviceSize *pCommittedMemoryInBytes)
2250 {
2251 *pCommittedMemoryInBytes = 0;
2252 }
2253
2254 void
v3dv_GetImageSparseMemoryRequirements(VkDevice device,VkImage image,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements * pSparseMemoryRequirements)2255 v3dv_GetImageSparseMemoryRequirements(
2256 VkDevice device,
2257 VkImage image,
2258 uint32_t *pSparseMemoryRequirementCount,
2259 VkSparseImageMemoryRequirements *pSparseMemoryRequirements)
2260 {
2261 *pSparseMemoryRequirementCount = 0;
2262 }
2263
2264 void
v3dv_GetImageSparseMemoryRequirements2(VkDevice device,const VkImageSparseMemoryRequirementsInfo2 * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)2265 v3dv_GetImageSparseMemoryRequirements2(
2266 VkDevice device,
2267 const VkImageSparseMemoryRequirementsInfo2 *pInfo,
2268 uint32_t *pSparseMemoryRequirementCount,
2269 VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
2270 {
2271 *pSparseMemoryRequirementCount = 0;
2272 }
2273
2274 /* vk_icd.h does not declare this function, so we declare it here to
2275 * suppress Wmissing-prototypes.
2276 */
2277 PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
2278 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion);
2279
2280 PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t * pSupportedVersion)2281 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion)
2282 {
2283 /* For the full details on loader interface versioning, see
2284 * <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>.
2285 * What follows is a condensed summary, to help you navigate the large and
2286 * confusing official doc.
2287 *
2288 * - Loader interface v0 is incompatible with later versions. We don't
2289 * support it.
2290 *
2291 * - In loader interface v1:
2292 * - The first ICD entrypoint called by the loader is
2293 * vk_icdGetInstanceProcAddr(). The ICD must statically expose this
2294 * entrypoint.
2295 * - The ICD must statically expose no other Vulkan symbol unless it is
2296 * linked with -Bsymbolic.
2297 * - Each dispatchable Vulkan handle created by the ICD must be
2298 * a pointer to a struct whose first member is VK_LOADER_DATA. The
2299 * ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC.
2300 * - The loader implements vkCreate{PLATFORM}SurfaceKHR() and
2301 * vkDestroySurfaceKHR(). The ICD must be capable of working with
2302 * such loader-managed surfaces.
2303 *
2304 * - Loader interface v2 differs from v1 in:
2305 * - The first ICD entrypoint called by the loader is
2306 * vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must
2307 * statically expose this entrypoint.
2308 *
2309 * - Loader interface v3 differs from v2 in:
2310 * - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(),
2311 * vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR,
2312 * because the loader no longer does so.
2313 *
2314 * - Loader interface v4 differs from v3 in:
2315 * - The ICD must implement vk_icdGetPhysicalDeviceProcAddr().
2316 */
2317 *pSupportedVersion = MIN2(*pSupportedVersion, 3u);
2318 return VK_SUCCESS;
2319 }
2320