summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-24 22:13:05 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-24 22:13:05 -0400
commitb43291c5420964424bfcf0aab0f1454c2c3b0613 (patch)
tree32e80a364b10610fb3f1cc58bbe9c6a07d16dfd7
parentade29f0c5df211ca9d32589196c8e59a2fd2ae76 (diff)
downloadopen-iov-b43291c5420964424bfcf0aab0f1454c2c3b0613.tar.gz
open-iov-b43291c5420964424bfcf0aab0f1454c2c3b0613.zip
tools/vk + nvkmstrace: real-Vulkan probe stack for the emulated vGPU - vk_probe/vk_probe2 (ctypes loader probes: enumerate + create device/queue), vk_frame (headless Vulkan compute renderer: loads the NVIDIA ICD, paints a plasma into an RGBA8 storage image, reads it back to PPM and publishes frames into the kvmfr ivshmem BAR), vk_plasma.comp -> SPIR-V; nvkmstrace.c (LD_PRELOAD NVKMS ioctl logger that decoded the vkCreateDevice failure to ALLOC_DEVICE cmd=0). Measured: the NVIDIA device enumerates and its Vulkan ICD loads (2 ICDs: NVIDIA + llvmpipe); vkCreateDevice fails VK_ERROR_INITIALIZATION_FAILED because nvKmsAllocDevice returns non-success after the display shim
-rw-r--r--tools/guest-diag/nvkmstrace.c47
-rw-r--r--tools/vk/vk_frame.c485
-rw-r--r--tools/vk/vk_plasma.comp17
-rw-r--r--tools/vk/vk_plasma.spvbin0 -> 2800 bytes
-rw-r--r--tools/vk/vk_plasma_spv.h237
-rw-r--r--tools/vk/vk_probe.py81
-rw-r--r--tools/vk/vk_probe2.py141
7 files changed, 1008 insertions, 0 deletions
diff --git a/tools/guest-diag/nvkmstrace.c b/tools/guest-diag/nvkmstrace.c
new file mode 100644
index 0000000..411de6b
--- /dev/null
+++ b/tools/guest-diag/nvkmstrace.c
@@ -0,0 +1,47 @@
+// nvkmstrace.c - LD_PRELOAD shim: log NVKMS_IOCTL_IOWR commands
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <dlfcn.h>
+#include <sys/ioctl.h>
+
+struct nvkms_ioctl_params {
+ uint32_t cmd;
+ uint32_t size;
+ uint64_t address;
+};
+
+#define NVKMS_REQ 0xC0106D00UL
+
+static int (*real_ioctl)(int, unsigned long, ...);
+
+int ioctl(int fd, unsigned long req, ...)
+{
+ va_list ap;
+ void *arg;
+
+ va_start(ap, req);
+ arg = va_arg(ap, void *);
+ va_end(ap);
+ if (!real_ioctl)
+ real_ioctl = dlsym(RTLD_NEXT, "ioctl");
+ if (req == NVKMS_REQ && arg) {
+ struct nvkms_ioctl_params *p = arg;
+ int rc;
+
+ rc = real_ioctl(fd, req, arg);
+ fprintf(stderr, "NVKMS_IOCTL cmd=%u size=%u addr=%p rc=%d\n",
+ p->cmd, p->size, (void *)(uintptr_t)p->address, rc);
+ if (p->address && p->size) {
+ unsigned char *q = (unsigned char *)(uintptr_t)p->address;
+ unsigned n = p->size < 64 ? p->size : 64, i;
+ fprintf(stderr, " data:");
+ for (i = 0; i < n; i++)
+ fprintf(stderr, " %02x", q[i]);
+ fprintf(stderr, "\n");
+ }
+ return rc;
+ }
+ return real_ioctl(fd, req, arg);
+}
diff --git a/tools/vk/vk_frame.c b/tools/vk/vk_frame.c
new file mode 100644
index 0000000..8b864ff
--- /dev/null
+++ b/tools/vk/vk_frame.c
@@ -0,0 +1,485 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * vk_frame.c - headless Vulkan render probe for the vGPU guest.
+ *
+ * Creates a real Vulkan device on the NVIDIA ICD, runs a compute shader that
+ * paints an animated plasma into an RGBA8 storage image, copies the image to
+ * a host-visible buffer, saves a PPM, and (optionally) publishes each frame
+ * into the kvmfr ivshmem BAR in the frame_producer layout so the host can
+ * display it. No window system involved (pure headless), so it works even
+ * while the GL/GLX walls are being fixed.
+ *
+ * Usage: ./vk_frame [frames] [width] [height] [fps] [outdir] [publish]
+ * Build: gcc -O2 -o vk_frame vk_frame.c -lvulkan (same glibc as the guest)
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <vulkan/vulkan.h>
+
+#include "vk_plasma_spv.h"
+
+#define FRAME_OFFSET 0x100000UL
+#define HDR_MAGIC 0x4b564d46u
+
+struct frame_hdr {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t format;
+ uint32_t seq;
+ uint32_t reserved;
+ uint64_t timestamp_ns;
+};
+
+static uint64_t now_ns(void)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (uint64_t)ts.tv_sec * 1000000000ull + ts.tv_nsec;
+}
+
+#define VKC(x) \
+ do { \
+ VkResult r_ = (x); \
+ if (r_ != VK_SUCCESS) { \
+ printf("VKFAIL %s -> %d (line %d)\n", #x, r_, \
+ __LINE__); \
+ return 1; \
+ } \
+ } while (0)
+
+int main(int argc, char **argv)
+{
+ int frames = argc > 1 ? atoi(argv[1]) : 60;
+ uint32_t W = argc > 2 ? (uint32_t)atoi(argv[2]) : 640;
+ uint32_t H = argc > 3 ? (uint32_t)atoi(argv[3]) : 480;
+ int fps = argc > 4 ? atoi(argv[4]) : 10;
+ const char *outdir = argc > 5 ? argv[5] : NULL;
+ int publish = argc > 6 ? atoi(argv[6]) : 1;
+ VkApplicationInfo app = {0};
+ VkInstanceCreateInfo ici = {0};
+ VkInstance inst;
+ uint32_t ndev = 0;
+ VkPhysicalDevice devs[16];
+ VkPhysicalDevice phys = VK_NULL_HANDLE;
+ char picked[256] = "";
+ uint32_t nfam = 0, fam = ~0u;
+ VkQueueFamilyProperties fams[16];
+ VkDevice dev;
+ VkQueue queue;
+ VkImage image;
+ VkDeviceMemory img_mem;
+ VkImageView view;
+ VkBuffer buf;
+ VkDeviceMemory buf_mem;
+ VkShaderModule shader;
+ VkDescriptorSetLayout dsl;
+ VkPipelineLayout pl;
+ VkPipeline pipe;
+ VkDescriptorPool pool;
+ VkDescriptorSet dset;
+ VkCommandPool cpool;
+ VkCommandBuffer cb;
+ VkFence fence;
+ uint32_t i;
+ float prio = 1.0f;
+ VkDeviceSize imgsz = (VkDeviceSize)W * H * 4;
+ unsigned char *pix;
+ struct frame_hdr *hdr = NULL;
+ volatile uint32_t *seqp = NULL;
+ unsigned char *bar = NULL;
+ int bfd = -1;
+ int saved = 0;
+ uint64_t t_first = 0, t_last = 0;
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ app.pApplicationName = "vk_frame";
+ app.pEngineName = "vk_frame";
+ app.apiVersion = VK_API_VERSION_1_2;
+ ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ ici.pApplicationInfo = &app;
+ VKC(vkCreateInstance(&ici, NULL, &inst));
+ printf("VKINSTANCE ok\n");
+
+ VKC(vkEnumeratePhysicalDevices(inst, &ndev, NULL));
+ if (ndev > 16)
+ ndev = 16;
+ VKC(vkEnumeratePhysicalDevices(inst, &ndev, devs));
+ printf("VKDEVS %u\n", ndev);
+ for (i = 0; i < ndev; i++) {
+ VkPhysicalDeviceProperties pp;
+
+ vkGetPhysicalDeviceProperties(devs[i], &pp);
+ printf("VKDEV %u: %s vendor=0x%04x\n", i, pp.deviceName,
+ pp.vendorID);
+ if (pp.vendorID == 0x10de || strstr(pp.deviceName, "NVIDIA")) {
+ phys = devs[i];
+ snprintf(picked, sizeof(picked), "%s",
+ pp.deviceName);
+ }
+ }
+ if (!phys) {
+ printf("VK_NO_NVIDIA\n");
+ return 2;
+ }
+ printf("VKPICK %s\n", picked);
+ vkGetPhysicalDeviceQueueFamilyProperties(phys, &nfam, NULL);
+ if (nfam > 16)
+ nfam = 16;
+ vkGetPhysicalDeviceQueueFamilyProperties(phys, &nfam, fams);
+ for (i = 0; i < nfam; i++)
+ if ((fams[i].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
+ fams[i].queueCount > 0) {
+ fam = i;
+ break;
+ }
+ if (fam == ~0u) {
+ printf("VK_NO_COMPUTE_QUEUE\n");
+ return 3;
+ }
+ {
+ VkDeviceQueueCreateInfo qci = {0};
+ VkDeviceCreateInfo dci = {0};
+
+ qci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ qci.queueFamilyIndex = fam;
+ qci.queueCount = 1;
+ qci.pQueuePriorities = &prio;
+ dci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+ dci.queueCreateInfoCount = 1;
+ dci.pQueueCreateInfos = &qci;
+ VKC(vkCreateDevice(phys, &dci, NULL, &dev));
+ }
+ printf("VKDEVICE ok family=%u\n", fam);
+ vkGetDeviceQueue(dev, fam, 0, &queue);
+
+ /* storage image */
+ {
+ VkImageCreateInfo ci = {0};
+ VkMemoryRequirements mr;
+ VkMemoryAllocateInfo ma = {0};
+
+ ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ ci.imageType = VK_IMAGE_TYPE_2D;
+ ci.format = VK_FORMAT_R8G8B8A8_UNORM;
+ ci.extent.width = W;
+ ci.extent.height = H;
+ ci.extent.depth = 1;
+ ci.mipLevels = 1;
+ ci.arrayLayers = 1;
+ ci.samples = VK_SAMPLE_COUNT_1_BIT;
+ ci.tiling = VK_IMAGE_TILING_OPTIMAL;
+ ci.usage = VK_IMAGE_USAGE_STORAGE_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ VKC(vkCreateImage(dev, &ci, NULL, &image));
+ vkGetImageMemoryRequirements(dev, image, &mr);
+ ma.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ ma.allocationSize = mr.size;
+ /* find a device-local memory type */
+ {
+ VkPhysicalDeviceMemoryProperties mp;
+ uint32_t k;
+
+ vkGetPhysicalDeviceMemoryProperties(phys, &mp);
+ for (k = 0; k < mp.memoryTypeCount; k++)
+ if ((mr.memoryTypeBits & (1u << k)) &&
+ (mp.memoryTypes[k].propertyFlags &
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
+ ma.memoryTypeIndex = k;
+ break;
+ }
+ }
+ VKC(vkAllocateMemory(dev, &ma, NULL, &img_mem));
+ VKC(vkBindImageMemory(dev, image, img_mem, 0));
+ }
+ {
+ VkImageViewCreateInfo ci = {0};
+
+ ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ ci.image = image;
+ ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ ci.format = VK_FORMAT_R8G8B8A8_UNORM;
+ ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ ci.subresourceRange.levelCount = 1;
+ ci.subresourceRange.layerCount = 1;
+ VKC(vkCreateImageView(dev, &ci, NULL, &view));
+ }
+ /* host-visible readback buffer */
+ {
+ VkBufferCreateInfo ci = {0};
+ VkMemoryRequirements mr;
+ VkMemoryAllocateInfo ma = {0};
+
+ ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ ci.size = imgsz;
+ ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ VKC(vkCreateBuffer(dev, &ci, NULL, &buf));
+ vkGetBufferMemoryRequirements(dev, buf, &mr);
+ ma.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ ma.allocationSize = mr.size;
+ {
+ VkPhysicalDeviceMemoryProperties mp;
+ uint32_t k;
+
+ vkGetPhysicalDeviceMemoryProperties(phys, &mp);
+ for (k = 0; k < mp.memoryTypeCount; k++)
+ if ((mr.memoryTypeBits & (1u << k)) &&
+ (mp.memoryTypes[k].propertyFlags &
+ (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))) {
+ ma.memoryTypeIndex = k;
+ break;
+ }
+ }
+ VKC(vkAllocateMemory(dev, &ma, NULL, &buf_mem));
+ VKC(vkBindBufferMemory(dev, buf, buf_mem, 0));
+ }
+ /* shader + pipeline */
+ {
+ VkShaderModuleCreateInfo ci = {0};
+ VkDescriptorSetLayoutBinding b = {0};
+ VkDescriptorSetLayoutCreateInfo dci = {0};
+ VkPushConstantRange pcr = {0};
+ VkPipelineLayoutCreateInfo plci = {0};
+ VkComputePipelineCreateInfo pci = {0};
+
+ ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ ci.codeSize = vk_plasma_spv_len;
+ ci.pCode = (const uint32_t *)vk_plasma_spv;
+ VKC(vkCreateShaderModule(dev, &ci, NULL, &shader));
+ b.binding = 0;
+ b.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ b.descriptorCount = 1;
+ b.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ dci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ dci.bindingCount = 1;
+ dci.pBindings = &b;
+ VKC(vkCreateDescriptorSetLayout(dev, &dci, NULL, &dsl));
+ pcr.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ pcr.size = 16;
+ plci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ plci.setLayoutCount = 1;
+ plci.pSetLayouts = &dsl;
+ plci.pushConstantRangeCount = 1;
+ plci.pPushConstantRanges = &pcr;
+ VKC(vkCreatePipelineLayout(dev, &plci, NULL, &pl));
+ pci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ pci.stage.sType =
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ pci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
+ pci.stage.module = shader;
+ pci.stage.pName = "main";
+ pci.layout = pl;
+ VKC(vkCreateComputePipelines(dev, VK_NULL_HANDLE, 1, &pci,
+ NULL, &pipe));
+ }
+ {
+ VkDescriptorPoolSize ps = {0};
+ VkDescriptorPoolCreateInfo pci = {0};
+ VkDescriptorSetAllocateInfo ai = {0};
+ VkDescriptorImageInfo ii = {0};
+ VkWriteDescriptorSet w = {0};
+
+ ps.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ ps.descriptorCount = 1;
+ pci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ pci.maxSets = 1;
+ pci.poolSizeCount = 1;
+ pci.pPoolSizes = &ps;
+ VKC(vkCreateDescriptorPool(dev, &pci, NULL, &pool));
+ ai.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ ai.descriptorPool = pool;
+ ai.descriptorSetCount = 1;
+ ai.pSetLayouts = &dsl;
+ VKC(vkAllocateDescriptorSets(dev, &ai, &dset));
+ ii.imageView = view;
+ ii.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+ w.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ w.dstSet = dset;
+ w.dstBinding = 0;
+ w.descriptorCount = 1;
+ w.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ w.pImageInfo = &ii;
+ vkUpdateDescriptorSets(dev, 1, &w, 0, NULL);
+ }
+ {
+ VkCommandPoolCreateInfo ci = {0};
+
+ ci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ ci.queueFamilyIndex = fam;
+ VKC(vkCreateCommandPool(dev, &ci, NULL, &cpool));
+ VkCommandBufferAllocateInfo ai = {0};
+
+ ai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ ai.commandPool = cpool;
+ ai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ ai.commandBufferCount = 1;
+ VKC(vkAllocateCommandBuffers(dev, &ai, &cb));
+ }
+ {
+ VkFenceCreateInfo ci = {0};
+
+ ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ VKC(vkCreateFence(dev, &ci, NULL, &fence));
+ }
+ if (publish) {
+ const char *bp =
+ "/sys/bus/pci/devices/0000:00:03.0/resource2";
+
+ bfd = open(bp, O_RDWR | O_SYNC);
+ if (bfd >= 0) {
+ bar = mmap(NULL, 128UL << 20, PROT_READ | PROT_WRITE,
+ MAP_SHARED, bfd, 0);
+ if (bar != MAP_FAILED) {
+ hdr = (struct frame_hdr *)(bar +
+ FRAME_OFFSET);
+ seqp = &hdr->seq;
+ hdr->magic = HDR_MAGIC;
+ hdr->version = 1;
+ hdr->width = W;
+ hdr->height = H;
+ hdr->stride = W * 4;
+ hdr->format = 0;
+ printf("PUBLISH on\n");
+ } else {
+ bar = NULL;
+ }
+ }
+ if (!bar)
+ printf("PUBLISH off (BAR open/mmap failed)\n");
+ }
+ VKC(vkMapMemory(dev, buf_mem, 0, imgsz, 0, (void **)&pix));
+
+ for (i = 0; i < (uint32_t)frames; i++) {
+ VkCommandBufferBeginInfo bi = {0};
+ VkImageMemoryBarrier ib = {0};
+ VkBufferImageCopy bc = {0};
+ VkBufferMemoryBarrier bb = {0};
+ float pc[4];
+ uint64_t t0 = now_ns();
+ VkSubmitInfo si = {0};
+ uint32_t gw = (W + 15) / 16, gh = (H + 15) / 16;
+
+ VKC(vkResetCommandBuffer(cb, 0));
+ bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ VKC(vkBeginCommandBuffer(cb, &bi));
+ ib.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ ib.srcAccessMask = 0;
+ ib.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ ib.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ ib.newLayout = VK_IMAGE_LAYOUT_GENERAL;
+ ib.image = image;
+ ib.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ ib.subresourceRange.levelCount = 1;
+ ib.subresourceRange.layerCount = 1;
+ vkCmdPipelineBarrier(cb,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0,
+ NULL, 0, NULL, 1, &ib);
+ vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
+ vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_COMPUTE, pl,
+ 0, 1, &dset, 0, NULL);
+ pc[0] = (float)i * 0.1f;
+ pc[1] = (float)W;
+ pc[2] = (float)H;
+ pc[3] = 0.0f;
+ vkCmdPushConstants(cb, pl, VK_SHADER_STAGE_COMPUTE_BIT, 0, 16,
+ pc);
+ vkCmdDispatch(cb, gw, gh, 1);
+ ib.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ ib.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ ib.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
+ ib.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ vkCmdPipelineBarrier(cb,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL,
+ 0, NULL, 1, &ib);
+ bc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ bc.imageSubresource.layerCount = 1;
+ bc.imageExtent.width = W;
+ bc.imageExtent.height = H;
+ bc.imageExtent.depth = 1;
+ vkCmdCopyImageToBuffer(cb, image,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ buf, 1, &bc);
+ bb.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+ bb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ bb.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
+ bb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ bb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ bb.buffer = buf;
+ bb.size = VK_WHOLE_SIZE;
+ vkCmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1,
+ &bb, 0, NULL);
+ VKC(vkEndCommandBuffer(cb));
+ si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ si.commandBufferCount = 1;
+ si.pCommandBuffers = &cb;
+ VKC(vkResetFences(dev, 1, &fence));
+ VKC(vkQueueSubmit(queue, 1, &si, fence));
+ VKC(vkWaitForFences(dev, 1, &fence, VK_TRUE, 30000000000ull));
+ vkUnmapMemory(dev, buf_mem);
+ vkMapMemory(dev, buf_mem, 0, imgsz, 0, (void **)&pix);
+
+ if (outdir) {
+ char path[512];
+ FILE *f;
+
+ snprintf(path, sizeof(path), "%s/vk-%04d.ppm",
+ outdir, i + 1);
+ f = fopen(path, "wb");
+ if (f) {
+ unsigned char *d = malloc((size_t)W * H * 3);
+ uint32_t p;
+
+ for (p = 0; p < W * H; p++) {
+ d[p * 3 + 0] = pix[p * 4 + 0];
+ d[p * 3 + 1] = pix[p * 4 + 1];
+ d[p * 3 + 2] = pix[p * 4 + 2];
+ }
+ fprintf(f, "P6\n%u %u\n255\n", W, H);
+ fwrite(d, 1, (size_t)W * H * 3, f);
+ fclose(f);
+ free(d);
+ saved++;
+ }
+ }
+ if (bar) {
+ memcpy(bar + FRAME_OFFSET + sizeof(struct frame_hdr),
+ pix, imgsz);
+ hdr->timestamp_ns = now_ns();
+ __sync_synchronize();
+ *seqp = (uint32_t)(i + 1);
+ __sync_synchronize();
+ }
+ if (!t_first)
+ t_first = t0;
+ t_last = t0;
+ if (i < 5 || (i % 30) == 29)
+ printf("VKFRAME seq=%d ms=%.1f\n", i + 1,
+ (double)(now_ns() - t0) / 1e6);
+ if (fps > 0)
+ usleep((useconds_t)(1000000 / fps));
+ }
+ if (t_first && t_last > t_first)
+ printf("VKFRAME_RATE fps=%.2f frames=%d\n",
+ (double)(i - 1) * 1e9 / (double)(t_last - t_first), i);
+ printf("VKFRAME_DONE frames=%d %ux%u saved=%d\n", i, W, H, saved);
+ vkDeviceWaitIdle(dev);
+ printf("VKFRAME_IDLE ok\n");
+ return 0;
+} \ No newline at end of file
diff --git a/tools/vk/vk_plasma.comp b/tools/vk/vk_plasma.comp
new file mode 100644
index 0000000..fe6b3ac
--- /dev/null
+++ b/tools/vk/vk_plasma.comp
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// vk_plasma.comp - compute-shader frame painter for the Vulkan guest test.
+#version 450
+layout(local_size_x = 16, local_size_y = 16) in;
+layout(set = 0, binding = 0, rgba8) uniform writeonly image2D fb;
+layout(push_constant) uniform PC { float t; float w; float h; float pad; } pc;
+void main() {
+ ivec2 p = ivec2(gl_GlobalInvocationID.xy);
+ if (p.x >= int(pc.w) || p.y >= int(pc.h))
+ return;
+ vec2 uv = vec2(p) / vec2(pc.w, pc.h);
+ float v = sin(uv.x * 12.0 + pc.t * 2.0) * cos(uv.y * 9.0 - pc.t * 1.7);
+ float r = 0.5 + 0.5 * sin(pc.t + uv.x * 6.2831);
+ float g = 0.5 + 0.5 * sin(pc.t * 1.3 + uv.y * 6.2831);
+ float b = 0.5 + 0.5 * v;
+ imageStore(fb, p, vec4(r, g, b, 1.0));
+}
diff --git a/tools/vk/vk_plasma.spv b/tools/vk/vk_plasma.spv
new file mode 100644
index 0000000..7c12b51
--- /dev/null
+++ b/tools/vk/vk_plasma.spv
Binary files differ
diff --git a/tools/vk/vk_plasma_spv.h b/tools/vk/vk_plasma_spv.h
new file mode 100644
index 0000000..49c16f1
--- /dev/null
+++ b/tools/vk/vk_plasma_spv.h
@@ -0,0 +1,237 @@
+unsigned char vk_plasma_spv[] = {
+ 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x08, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0xc2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61,
+ 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49,
+ 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x50, 0x43, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x68, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x1a, 0x00, 0x00, 0x00, 0x70, 0x63, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x53, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x5f, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x6b, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+ 0x71, 0x00, 0x00, 0x00, 0x66, 0x62, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x47, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x23, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
+ 0x71, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+ 0x71, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x47, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x7b, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x41, 0x2b, 0x00, 0x04, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x2b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x41, 0x2b, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x9a, 0x99, 0xd9, 0x3f,
+ 0x2b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x59, 0x00, 0x00, 0x00, 0x28, 0x0f, 0xc9, 0x40, 0x2b, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x66, 0x66, 0xa6, 0x3f,
+ 0x19, 0x00, 0x09, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x00,
+ 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
+ 0x17, 0x00, 0x04, 0x00, 0x78, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+ 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x3b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00,
+ 0x5f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+ 0x3b, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
+ 0x6e, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0xa8, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
+ 0x22, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x05, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x2a, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00,
+ 0xf8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+ 0xf7, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfa, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x2d, 0x00, 0x00, 0x00,
+ 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x04, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x1b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x27, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x3a, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x03, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x05, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x44, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x46, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x06, 0x00, 0x17, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x05, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
+ 0x49, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x4d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x4e, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x06, 0x00, 0x17, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
+ 0x47, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x56, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
+ 0x3b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x59, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x5b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x06, 0x00, 0x17, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x5d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x53, 0x00, 0x00, 0x00,
+ 0x5e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x63, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x05, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x67, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x69, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
+ 0x81, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
+ 0x5f, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+ 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x6d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x6b, 0x00, 0x00, 0x00,
+ 0x6e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x6f, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x75, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x07, 0x00, 0x78, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x73, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
+ 0x38, 0x00, 0x01, 0x00
+};
+unsigned int vk_plasma_spv_len = 2800;
diff --git a/tools/vk/vk_probe.py b/tools/vk/vk_probe.py
new file mode 100644
index 0000000..3113c3f
--- /dev/null
+++ b/tools/vk/vk_probe.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+# vk_probe.py - enumerate real Vulkan physical devices via the loader (ctypes,
+# no dev headers needed). Prints one DEV line per physical device.
+import ctypes
+import sys
+
+VK_SUCCESS = 0
+VK_STRUCTURE_TYPE_APPLICATION_INFO = 0
+VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1
+VK_API_VERSION_1_2 = (1 << 22) | (2 << 12)
+
+try:
+ vulkan = ctypes.CDLL("libvulkan.so.1")
+except OSError as e:
+ print("LOAD_FAIL %s" % e)
+ sys.exit(1)
+
+
+class VkApplicationInfo(ctypes.Structure):
+ _fields_ = [
+ ("sType", ctypes.c_int),
+ ("pNext", ctypes.c_void_p),
+ ("pApplicationName", ctypes.c_char_p),
+ ("applicationVersion", ctypes.c_uint32),
+ ("pEngineName", ctypes.c_char_p),
+ ("engineVersion", ctypes.c_uint32),
+ ("apiVersion", ctypes.c_uint32),
+ ]
+
+
+class VkInstanceCreateInfo(ctypes.Structure):
+ _fields_ = [
+ ("sType", ctypes.c_int),
+ ("pNext", ctypes.c_void_p),
+ ("flags", ctypes.c_uint32),
+ ("pApplicationInfo", ctypes.POINTER(VkApplicationInfo)),
+ ("enabledLayerCount", ctypes.c_uint32),
+ ("ppEnabledLayerNames", ctypes.c_void_p),
+ ("enabledExtensionCount", ctypes.c_uint32),
+ ("ppEnabledExtensionNames", ctypes.c_void_p),
+ ]
+
+
+app = VkApplicationInfo(
+ VK_STRUCTURE_TYPE_APPLICATION_INFO, None, b"vk_probe", 1, b"vk_probe", 1,
+ VK_API_VERSION_1_2)
+ci = VkInstanceCreateInfo(
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, None, 0, ctypes.pointer(app), 0,
+ None, 0, None)
+inst = ctypes.c_void_p()
+r = vulkan.vkCreateInstance(ctypes.byref(ci), None, ctypes.byref(inst))
+print("vkCreateInstance rc=%d (0x%x)" % (r, r & 0xfffffffff if r < 0 else r))
+if r != VK_SUCCESS:
+ sys.exit(1)
+
+n = ctypes.c_uint32(0)
+r = vulkan.vkEnumeratePhysicalDevices(inst, ctypes.byref(n), None)
+print("vkEnumeratePhysicalDevices rc=%d count=%d" % (r, n.value))
+if r != VK_SUCCESS or n.value == 0:
+ sys.exit(2)
+
+devs = (ctypes.c_void_p * n.value)()
+r = vulkan.vkEnumeratePhysicalDevices(inst, ctypes.byref(n), devs)
+ok = 0
+for i in range(n.value):
+ buf = ctypes.create_string_buffer(4096)
+ vulkan.vkGetPhysicalDeviceProperties(devs[i], buf)
+ raw = buf.raw
+ api = int.from_bytes(raw[0:4], "little")
+ drv = int.from_bytes(raw[4:8], "little")
+ vendor = int.from_bytes(raw[8:12], "little")
+ devid = int.from_bytes(raw[12:16], "little")
+ dtype = int.from_bytes(raw[16:20], "little")
+ name = raw[20:20 + 256].split(b"\x00")[0].decode("utf-8", "replace")
+ print("DEV %d: %s vendor=0x%04x device=0x%04x type=%d api=%d.%d.%d drv=%d"
+ % (i, name, vendor, devid, dtype, api >> 22,
+ (api >> 12) & 0x3ff, api & 0xfff, drv))
+ if vendor == 0x10de:
+ ok = 1
+print("VK_NVIDIA=%d" % ok)
+sys.exit(0 if ok else 3) \ No newline at end of file
diff --git a/tools/vk/vk_probe2.py b/tools/vk/vk_probe2.py
new file mode 100644
index 0000000..557b888
--- /dev/null
+++ b/tools/vk/vk_probe2.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python3
+# vk_probe2.py - Vulkan probe stage 2: create a logical device + queue on the
+# NVIDIA physical device. Prints the queue-family table and the create
+# result. ctypes only, no dev headers.
+import ctypes
+import sys
+
+VK_SUCCESS = 0
+VK_STRUCTURE_TYPE_APPLICATION_INFO = 0
+VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1
+VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2
+VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3
+VK_API_VERSION_1_2 = (1 << 22) | (2 << 12)
+
+vulkan = ctypes.CDLL("libvulkan.so.1")
+
+
+class VkApplicationInfo(ctypes.Structure):
+ _fields_ = [
+ ("sType", ctypes.c_int),
+ ("pNext", ctypes.c_void_p),
+ ("pApplicationName", ctypes.c_char_p),
+ ("applicationVersion", ctypes.c_uint32),
+ ("pEngineName", ctypes.c_char_p),
+ ("engineVersion", ctypes.c_uint32),
+ ("apiVersion", ctypes.c_uint32),
+ ]
+
+
+class VkInstanceCreateInfo(ctypes.Structure):
+ _fields_ = [
+ ("sType", ctypes.c_int),
+ ("pNext", ctypes.c_void_p),
+ ("flags", ctypes.c_uint32),
+ ("pApplicationInfo", ctypes.POINTER(VkApplicationInfo)),
+ ("enabledLayerCount", ctypes.c_uint32),
+ ("ppEnabledLayerNames", ctypes.c_void_p),
+ ("enabledExtensionCount", ctypes.c_uint32),
+ ("ppEnabledExtensionNames", ctypes.c_void_p),
+ ]
+
+
+class VkQueueFamilyProperties(ctypes.Structure):
+ _fields_ = [
+ ("queueFlags", ctypes.c_uint32),
+ ("queueCount", ctypes.c_uint32),
+ ("timestampValidBits", ctypes.c_uint32),
+ ("minImageTransferGranularity", ctypes.c_uint8 * 12),
+ ]
+
+
+class VkDeviceQueueCreateInfo(ctypes.Structure):
+ _fields_ = [
+ ("sType", ctypes.c_int),
+ ("pNext", ctypes.c_void_p),
+ ("flags", ctypes.c_uint32),
+ ("queueFamilyIndex", ctypes.c_uint32),
+ ("queueCount", ctypes.c_uint32),
+ ("pQueuePriorities", ctypes.POINTER(ctypes.c_float)),
+ ]
+
+
+class VkDeviceCreateInfo(ctypes.Structure):
+ _fields_ = [
+ ("sType", ctypes.c_int),
+ ("pNext", ctypes.c_void_p),
+ ("flags", ctypes.c_uint32),
+ ("queueCreateInfoCount", ctypes.c_uint32),
+ ("pQueueCreateInfos", ctypes.POINTER(VkDeviceQueueCreateInfo)),
+ ("enabledLayerCount", ctypes.c_uint32),
+ ("ppEnabledLayerNames", ctypes.c_void_p),
+ ("enabledExtensionCount", ctypes.c_uint32),
+ ("ppEnabledExtensionNames", ctypes.c_void_p),
+ ("pEnabledFeatures", ctypes.c_void_p),
+ ]
+
+
+app = VkApplicationInfo(VK_STRUCTURE_TYPE_APPLICATION_INFO, None, b"vk_probe2",
+ 1, b"vk_probe2", 1, VK_API_VERSION_1_2)
+ci = VkInstanceCreateInfo(VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, None, 0,
+ ctypes.pointer(app), 0, None, 0, None)
+inst = ctypes.c_void_p()
+r = vulkan.vkCreateInstance(ctypes.byref(ci), None, ctypes.byref(inst))
+print("INSTANCE rc=%d" % r)
+if r != 0:
+ sys.exit(1)
+
+n = ctypes.c_uint32(0)
+vulkan.vkEnumeratePhysicalDevices(inst, ctypes.byref(n), None)
+devs = (ctypes.c_void_p * n.value)()
+vulkan.vkEnumeratePhysicalDevices(inst, ctypes.byref(n), devs)
+
+# pick the NVIDIA device by name
+best = None
+for i in range(n.value):
+ buf = ctypes.create_string_buffer(4096)
+ vulkan.vkGetPhysicalDeviceProperties(devs[i], buf)
+ raw = buf.raw
+ name = raw[20:276].split(b"\x00")[0].decode("utf-8", "replace")
+ print("PROPS dev=%d head=%s name=%r" % (i, raw[:40].hex(), name))
+ if "NVIDIA" in name or "llvmpipe" in name:
+ if "NVIDIA" in name:
+ best = devs[i]
+ print("PICK NVIDIA dev=%d name=%s" % (i, name))
+ break
+if best is None:
+ print("NO_NVIDIA")
+ sys.exit(2)
+
+nfam = ctypes.c_uint32(0)
+vulkan.vkGetPhysicalDeviceQueueFamilyProperties(best, ctypes.byref(nfam),
+ None)
+fams = (VkQueueFamilyProperties * nfam.value)()
+vulkan.vkGetPhysicalDeviceQueueFamilyProperties(best, ctypes.byref(nfam),
+ fams)
+gfam = None
+for j in range(nfam.value):
+ print("QFAM %d flags=0x%x count=%d" % (j, fams[j].queueFlags,
+ fams[j].queueCount))
+ if (fams[j].queueFlags & 0x1) and fams[j].queueCount > 0 and gfam is None:
+ gfam = j
+if gfam is None:
+ print("NO_GRAPHICS_QUEUE")
+ sys.exit(3)
+prio = ctypes.c_float(1.0)
+qci = VkDeviceQueueCreateInfo(VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ None, 0, gfam, 1, ctypes.pointer(prio))
+dci = VkDeviceCreateInfo(VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, None, 0, 1,
+ ctypes.pointer(qci), 0, None, 0, None, None)
+dev = ctypes.c_void_p()
+r = vulkan.vkCreateDevice(best, ctypes.byref(dci), None, ctypes.byref(dev))
+print("vkCreateDevice rc=%d (0x%x)" % (r, r if r < 0 else 0))
+if r != 0:
+ sys.exit(4)
+queue = ctypes.c_void_p()
+vulkan.vkGetDeviceQueue(dev, gfam, 0, ctypes.byref(queue))
+print("QUEUE device=%s queue=%s" % (bool(dev), bool(queue)))
+# optional: wait-idle (exercises the queue)
+vulkan.vkDeviceWaitIdle(dev)
+print("VK2_DEVICE_OK")
+sys.exit(0) \ No newline at end of file