vulkan_test2

changeset 4:c31c4115d44a

test 2, open window, create queue, etc ...
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 22 Sep 2017 15:26:29 +0300
parents 68e1c437343f
children cec4b0e7fce8
files .hgignore Makefile src/main.c src/vku.c src/vku.h src/wsys.h src/wsys_x11.c
diffstat 7 files changed, 577 insertions(+), 21 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Fri Sep 22 15:26:29 2017 +0300
     1.3 @@ -0,0 +1,4 @@
     1.4 +\.o$
     1.5 +\.swp$
     1.6 +\.d$
     1.7 +^test$
     2.1 --- a/Makefile	Fri Sep 22 01:01:10 2017 +0300
     2.2 +++ b/Makefile	Fri Sep 22 15:26:29 2017 +0300
     2.3 @@ -3,7 +3,7 @@
     2.4  bin = test
     2.5  
     2.6  CFLAGS = -pedantic -Wall -g
     2.7 -LDFLAGS = -lvulkan
     2.8 +LDFLAGS = -lvulkan -lX11
     2.9  
    2.10  $(bin): $(obj)
    2.11  	$(CC) -o $@ $(obj) $(LDFLAGS)
     3.1 --- a/src/main.c	Fri Sep 22 01:01:10 2017 +0300
     3.2 +++ b/src/main.c	Fri Sep 22 15:26:29 2017 +0300
     3.3 @@ -1,13 +1,45 @@
     3.4  #include <stdio.h>
     3.5 -#include <vulkan/vulkan.h>
     3.6 +#include "wsys.h"
     3.7  #include "vku.h"
     3.8  
     3.9 +static void display(void);
    3.10 +static void reshape(int x, int y);
    3.11 +static void keyboard(int key, int pressed);
    3.12 +
    3.13  int main(void)
    3.14  {
    3.15  	if(vku_create_dev() == -1) {
    3.16 -		return -1;
    3.17 +		return 1;
    3.18  	}
    3.19  
    3.20 +	if(wsys_create_window(800, 600) == -1) {
    3.21 +		return 1;
    3.22 +	}
    3.23 +	wsys_set_window_title("Vulkan test 2");
    3.24 +
    3.25 +	wsys_display_callback(display);
    3.26 +	wsys_reshape_callback(reshape);
    3.27 +	wsys_keyboard_callback(keyboard);
    3.28 +
    3.29 +	while(wsys_process_events(WSYS_BLOCKING) != -1);
    3.30 +
    3.31 +	wsys_destroy_window();
    3.32  	vku_cleanup();
    3.33  	return 0;
    3.34  }
    3.35 +
    3.36 +static void display(void)
    3.37 +{
    3.38 +	wsys_swap_buffers();
    3.39 +}
    3.40 +
    3.41 +static void reshape(int x, int y)
    3.42 +{
    3.43 +}
    3.44 +
    3.45 +static void keyboard(int key, int pressed)
    3.46 +{
    3.47 +	if(key == 27) {
    3.48 +		wsys_quit();
    3.49 +	}
    3.50 +}
     4.1 --- a/src/vku.c	Fri Sep 22 01:01:10 2017 +0300
     4.2 +++ b/src/vku.c	Fri Sep 22 15:26:29 2017 +0300
     4.3 @@ -1,7 +1,7 @@
     4.4  #include <stdio.h>
     4.5  #include <stdlib.h>
     4.6  #include <string.h>
     4.7 -#include <alloca.h>
     4.8 +#include <stdint.h>
     4.9  #include "vku.h"
    4.10  
    4.11  static const char *get_device_name(VkPhysicalDeviceType type);
    4.12 @@ -12,26 +12,108 @@
    4.13  static int ver_patch(uint32_t ver);
    4.14  static const char *mem_size_str(long sz);
    4.15  
    4.16 -
    4.17  VkInstance vk;
    4.18  VkDevice vkdev;
    4.19  VkQueue vkq;
    4.20  
    4.21 +static VkPhysicalDevice *phys_devices;
    4.22 +static int sel_dev, sel_qfamily;
    4.23 +
    4.24 +static VkExtensionProperties *vkext, *vkdevext;
    4.25 +static uint32_t vkext_count, vkdevext_count;
    4.26 +
    4.27 +
    4.28 +int vku_have_extension(const char *name)
    4.29 +{
    4.30 +	int i;
    4.31 +
    4.32 +	if(!vkext) {
    4.33 +		vkext_count = 0;
    4.34 +		vkEnumerateInstanceExtensionProperties(0, &vkext_count, 0);
    4.35 +		if(vkext_count) {
    4.36 +			if(!(vkext = malloc(vkext_count * sizeof *vkext))) {
    4.37 +				perror("failed to allocate instance extension list");
    4.38 +				return 0;
    4.39 +			}
    4.40 +			vkEnumerateInstanceExtensionProperties(0, &vkext_count, vkext);
    4.41 +
    4.42 +			printf("instance extensions:\n");
    4.43 +			for(i=0; i<(int)vkext_count; i++) {
    4.44 +				printf(" %s (ver: %u)\n", vkext[i].extensionName, (unsigned int)vkext[i].specVersion);
    4.45 +			}
    4.46 +		}
    4.47 +	}
    4.48 +
    4.49 +	for(i=0; i<(int)vkext_count; i++) {
    4.50 +		if(strcmp(vkext[i].extensionName, name) == 0) {
    4.51 +			return 1;
    4.52 +		}
    4.53 +	}
    4.54 +	return 0;
    4.55 +}
    4.56 +
    4.57 +int vku_have_device_extension(const char *name)
    4.58 +{
    4.59 +	int i;
    4.60 +
    4.61 +	if(sel_dev < 0) return 0;
    4.62 +
    4.63 +	if(!vkdevext) {
    4.64 +		vkdevext_count = 0;
    4.65 +		vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, 0);
    4.66 +		if(vkdevext_count) {
    4.67 +			if(!(vkdevext = malloc(vkdevext_count * sizeof *vkdevext))) {
    4.68 +				perror("failed to allocate device extension list");
    4.69 +				return 0;
    4.70 +			}
    4.71 +			vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, vkdevext);
    4.72 +
    4.73 +			printf("selected device extensions:\n");
    4.74 +			for(i=0; i<(int)vkdevext_count; i++) {
    4.75 +				printf(" %s (ver: %u)\n", vkdevext[i].extensionName, (unsigned int)vkdevext[i].specVersion);
    4.76 +			}
    4.77 +		}
    4.78 +	}
    4.79 +
    4.80 +	for(i=0; i<(int)vkdevext_count; i++) {
    4.81 +		if(strcmp(vkdevext[i].extensionName, name) == 0) {
    4.82 +			return 1;
    4.83 +		}
    4.84 +	}
    4.85 +	return 0;
    4.86 +}
    4.87 +
    4.88  int vku_create_dev(void)
    4.89  {
    4.90  	int i, j;
    4.91  	VkInstanceCreateInfo inst_info;
    4.92 -	VkPhysicalDevice *devices;
    4.93  	VkDeviceCreateInfo dev_info;
    4.94  	VkDeviceQueueCreateInfo queue_info;
    4.95  	VkCommandPoolCreateInfo cmdpool_info;
    4.96  	uint32_t num_devices;
    4.97 -	int sel_dev = -1;
    4.98 -	int sel_qfamily = -1;
    4.99  	float qprio = 0.0f;
   4.100  
   4.101 +	static const char *ext_names[] = {
   4.102 +#ifdef VK_USE_PLATFORM_XLIB_KHR
   4.103 +		"VK_KHR_xlib_surface",
   4.104 +#endif
   4.105 +		"VK_KHR_surface"
   4.106 +	};
   4.107 +
   4.108 +	sel_dev = -1;
   4.109 +	sel_qfamily = -1;
   4.110 +
   4.111 +	for(i=0; i<sizeof ext_names / sizeof *ext_names; i++) {
   4.112 +		if(!vku_have_extension(ext_names[i])) {
   4.113 +			fprintf(stderr, "required extension (%s) not found\n", ext_names[i]);
   4.114 +			return -1;
   4.115 +		}
   4.116 +	}
   4.117 +
   4.118  	memset(&inst_info, 0, sizeof inst_info);
   4.119  	inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
   4.120 +	inst_info.ppEnabledExtensionNames = ext_names;
   4.121 +	inst_info.enabledExtensionCount = sizeof ext_names / sizeof *ext_names;
   4.122  
   4.123  	if(vkCreateInstance(&inst_info, 0, &vk) != 0) {
   4.124  		fprintf(stderr, "failed to create vulkan instance\n");
   4.125 @@ -43,8 +125,8 @@
   4.126  		fprintf(stderr, "failed to enumerate vulkan physical devices\n");
   4.127  		return -1;
   4.128  	}
   4.129 -	devices = alloca(num_devices * sizeof *devices);
   4.130 -	if(vkEnumeratePhysicalDevices(vk, &num_devices, devices) != 0) {
   4.131 +	phys_devices = malloc(num_devices * sizeof *phys_devices);
   4.132 +	if(vkEnumeratePhysicalDevices(vk, &num_devices, phys_devices) != 0) {
   4.133  		fprintf(stderr, "failed to enumerate vulkan physical devices\n");
   4.134  		return -1;
   4.135  	}
   4.136 @@ -56,7 +138,7 @@
   4.137  		VkQueueFamilyProperties *qprop;
   4.138  		uint32_t qprop_count;
   4.139  
   4.140 -		vkGetPhysicalDeviceProperties(devices[i], &dev_prop);
   4.141 +		vkGetPhysicalDeviceProperties(phys_devices[i], &dev_prop);
   4.142  
   4.143  		printf("Device %d: %s\n", i, dev_prop.deviceName);
   4.144  		printf("  type: %s\n", get_device_name(dev_prop.deviceType));
   4.145 @@ -67,7 +149,7 @@
   4.146  		printf("  vendor id: %x  device id: %x\n", dev_prop.vendorID, dev_prop.deviceID);
   4.147  
   4.148  
   4.149 -		vkGetPhysicalDeviceMemoryProperties(devices[i], &mem_prop);
   4.150 +		vkGetPhysicalDeviceMemoryProperties(phys_devices[i], &mem_prop);
   4.151  		printf("  %d memory heaps:\n", mem_prop.memoryHeapCount);
   4.152  		for(j=0; j<mem_prop.memoryHeapCount; j++) {
   4.153  			VkMemoryHeap heap = mem_prop.memoryHeaps[j];
   4.154 @@ -81,12 +163,12 @@
   4.155  					get_mem_prop_flag_string(type.propertyFlags));
   4.156  		}
   4.157  
   4.158 -		vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &qprop_count, 0);
   4.159 +		vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, 0);
   4.160  		if(qprop_count <= 0) {
   4.161  			continue;
   4.162  		}
   4.163  		qprop = malloc(qprop_count * sizeof *qprop);
   4.164 -		vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &qprop_count, qprop);
   4.165 +		vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, qprop);
   4.166  
   4.167  		for(j=0; j<qprop_count; j++) {
   4.168  			printf("  Queue family %d:\n", j);
   4.169 @@ -119,7 +201,7 @@
   4.170  	dev_info.queueCreateInfoCount = 1;
   4.171  	dev_info.pQueueCreateInfos = &queue_info;
   4.172  
   4.173 -	if(vkCreateDevice(devices[sel_dev], &dev_info, 0, &vkdev) != 0) {
   4.174 +	if(vkCreateDevice(phys_devices[sel_dev], &dev_info, 0, &vkdev) != 0) {
   4.175  		fprintf(stderr, "failed to create device %d\n", sel_dev);
   4.176  		return -1;
   4.177  	}
   4.178 @@ -138,6 +220,11 @@
   4.179  		return -1;
   4.180  	}
   4.181  
   4.182 +	if(!(vkcmdbuf = vku_alloc_cmdbuf(vkcmdpool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))) {
   4.183 +		fprintf(stderr, "failed to create primary command buffer\n");
   4.184 +		return -1;
   4.185 +	}
   4.186 +
   4.187  	return 0;
   4.188  }
   4.189  
   4.190 @@ -145,15 +232,75 @@
   4.191  {
   4.192  	if(vk) {
   4.193  		vkDeviceWaitIdle(vkdev);
   4.194 +		vkDestroyCommandPool(vkdev, vkcmdpool, 0);
   4.195  		vkDestroyDevice(vkdev, 0);
   4.196  		vkDestroyInstance(vk, 0);
   4.197  		vk = 0;
   4.198  	}
   4.199 +
   4.200 +	free(phys_devices);
   4.201 +	phys_devices = 0;
   4.202  }
   4.203  
   4.204 -struct vk_buffer *vku_create_buffer(int sz, unsigned int usage)
   4.205 +VkCommandBuffer vku_alloc_cmdbuf(VkCommandPool pool, VkCommandBufferLevel level)
   4.206  {
   4.207 -	struct vk_buffer *buf;
   4.208 +	VkCommandBuffer cmdbuf;
   4.209 +	VkCommandBufferAllocateInfo inf;
   4.210 +
   4.211 +	memset(&inf, 0, sizeof inf);
   4.212 +	inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
   4.213 +	inf.commandPool = pool;
   4.214 +	inf.level = level;
   4.215 +	inf.commandBufferCount = 1;
   4.216 +
   4.217 +	if(vkAllocateCommandBuffers(vkdev, &inf, &cmdbuf) != 0) {
   4.218 +		return 0;
   4.219 +	}
   4.220 +	return cmdbuf;
   4.221 +}
   4.222 +
   4.223 +void vku_free_cmdbuf(VkCommandPool pool, VkCommandBuffer buf)
   4.224 +{
   4.225 +	vkFreeCommandBuffers(vkdev, pool, 1, &buf);
   4.226 +}
   4.227 +
   4.228 +void vku_begin_cmdbuf(VkCommandBuffer buf, unsigned int flags)
   4.229 +{
   4.230 +	VkCommandBufferBeginInfo inf;
   4.231 +
   4.232 +	memset(&inf, 0, sizeof inf);
   4.233 +	inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
   4.234 +	inf.flags = flags;
   4.235 +
   4.236 +	vkBeginCommandBuffer(buf, &inf);
   4.237 +}
   4.238 +
   4.239 +
   4.240 +void vku_end_cmdbuf(VkCommandBuffer buf)
   4.241 +{
   4.242 +	vkEndCommandBuffer(buf);
   4.243 +}
   4.244 +
   4.245 +void vku_reset_cmdbuf(VkCommandBuffer buf)
   4.246 +{
   4.247 +	vkResetCommandBuffer(buf, 0);
   4.248 +}
   4.249 +
   4.250 +void vku_submit_cmdbuf(VkQueue q, VkCommandBuffer buf, VkFence done_fence)
   4.251 +{
   4.252 +	VkSubmitInfo info;
   4.253 +
   4.254 +	memset(&info, 0, sizeof info);
   4.255 +	info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
   4.256 +	info.commandBufferCount = 1;
   4.257 +	info.pCommandBuffers = &buf;
   4.258 +
   4.259 +	vkQueueSubmit(q, 1, &info, done_fence);
   4.260 +}
   4.261 +
   4.262 +struct vku_buffer *vku_create_buffer(int sz, unsigned int usage)
   4.263 +{
   4.264 +	struct vku_buffer *buf;
   4.265  	VkBufferCreateInfo binfo;
   4.266  
   4.267  	if(!(buf = malloc(sizeof *buf))) {
   4.268 @@ -175,7 +322,7 @@
   4.269  	return buf;
   4.270  }
   4.271  
   4.272 -void vku_destroy_buffer(struct vk_buffer *buf)
   4.273 +void vku_destroy_buffer(struct vku_buffer *buf)
   4.274  {
   4.275  	if(buf) {
   4.276  		vkDestroyBuffer(vkdev, buf->buf, 0);
   4.277 @@ -183,6 +330,25 @@
   4.278  	}
   4.279  }
   4.280  
   4.281 +void vku_cmd_copybuf(VkCommandBuffer cmdbuf, VkBuffer dest, int doffs,
   4.282 +		VkBuffer src, int soffs, int size)
   4.283 +{
   4.284 +	VkBufferCopy copy;
   4.285 +	copy.size = size;
   4.286 +	copy.srcOffset = soffs;
   4.287 +	copy.dstOffset = doffs;
   4.288 +
   4.289 +	vkCmdCopyBuffer(cmdbuf, src, dest, 1, &copy);
   4.290 +}
   4.291 +
   4.292 +#ifdef VK_USE_PLATFORM_XLIB_KHR
   4.293 +int vku_xlib_usable_visual(Display *dpy, VisualID vid)
   4.294 +{
   4.295 +	return vkGetPhysicalDeviceXlibPresentationSupportKHR(phys_devices[sel_dev],
   4.296 +			sel_qfamily, dpy, vid);
   4.297 +}
   4.298 +#endif	/* VK_USE_PLATFORM_XLIB_KHR */
   4.299 +
   4.300  static const char *get_device_name(VkPhysicalDeviceType type)
   4.301  {
   4.302  	switch(type) {
     5.1 --- a/src/vku.h	Fri Sep 22 01:01:10 2017 +0300
     5.2 +++ b/src/vku.h	Fri Sep 22 15:26:29 2017 +0300
     5.3 @@ -1,24 +1,49 @@
     5.4  #ifndef VKU_H_
     5.5  #define VKU_H_
     5.6  
     5.7 +#ifdef __unix__
     5.8 +#define VK_USE_PLATFORM_XLIB_KHR
     5.9 +#endif
    5.10 +
    5.11  #include <vulkan/vulkan.h>
    5.12  
    5.13  VkInstance vk;
    5.14  VkDevice vkdev;
    5.15  VkQueue vkq;
    5.16  VkCommandPool vkcmdpool;
    5.17 +VkCommandBuffer vkcmdbuf;	/* primary command buffer */
    5.18  
    5.19 -struct vk_buffer {
    5.20 +struct vku_buffer {
    5.21  	VkBuffer buf;
    5.22  	VkDeviceMemory mem_pool;
    5.23  	int mem_start, mem_size;
    5.24  };
    5.25  
    5.26 +int vku_have_extension(const char *name);
    5.27 +int vku_have_device_extension(const char *name);
    5.28 +
    5.29  int vku_create_dev(void);
    5.30  void vku_cleanup(void);
    5.31  
    5.32 +VkCommandBuffer vku_alloc_cmdbuf(VkCommandPool pool, VkCommandBufferLevel level);
    5.33 +void vku_free_cmdbuf(VkCommandPool pool, VkCommandBuffer buf);
    5.34  
    5.35 -struct vk_buffer *vku_create_buffer(int sz, unsigned int usage);
    5.36 -void vku_destroy_buffer(struct vk_buffer *buf);
    5.37 +void vku_begin_cmdbuf(VkCommandBuffer buf, unsigned int flags);
    5.38 +void vku_end_cmdbuf(VkCommandBuffer buf);
    5.39 +void vku_reset_cmdbuf(VkCommandBuffer buf);
    5.40 +
    5.41 +void vku_submit_cmdbuf(VkQueue q, VkCommandBuffer buf, VkFence done_fence);
    5.42 +
    5.43 +struct vku_buffer *vku_create_buffer(int sz, unsigned int usage);
    5.44 +void vku_destroy_buffer(struct vku_buffer *buf);
    5.45 +
    5.46 +void vku_cmd_copybuf(VkCommandBuffer cmdbuf, VkBuffer dest, int doffs,
    5.47 +		VkBuffer src, int soffs, int size);
    5.48 +
    5.49 +/* platform-specific */
    5.50 +#ifdef VK_USE_PLATFORM_XLIB_KHR
    5.51 +#include <X11/Xlib.h>
    5.52 +int vku_xlib_usable_visual(Display *dpy, VisualID vid);
    5.53 +#endif
    5.54  
    5.55  #endif	/* VKU_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/wsys.h	Fri Sep 22 15:26:29 2017 +0300
     6.3 @@ -0,0 +1,31 @@
     6.4 +#ifndef WSYS_H_
     6.5 +#define WSYS_H_
     6.6 +
     6.7 +/* pass to wsys_process_events */
     6.8 +enum {
     6.9 +	WSYS_BLOCKING = 0,
    6.10 +	WSYS_NONBLOCK = 1
    6.11 +};
    6.12 +
    6.13 +int wsys_create_window(int xsz, int ysz);
    6.14 +void wsys_destroy_window(void);
    6.15 +
    6.16 +void wsys_set_window_title(const char *title);
    6.17 +void wsys_get_window_size(int *xsz, int *ysz);
    6.18 +
    6.19 +void wsys_display_callback(void (*func)(void));
    6.20 +void wsys_reshape_callback(void (*func)(int, int));
    6.21 +void wsys_keyboard_callback(void (*func)(int, int));
    6.22 +void wsys_mouse_callback(void (*func)(int, int, int, int));
    6.23 +void wsys_motion_callback(void (*func)(int, int));
    6.24 +void wsys_passive_motion_callback(void (*func)(int, int));
    6.25 +
    6.26 +void wsys_swap_buffers(void);
    6.27 +void wsys_redisplay(void);
    6.28 +void wsys_quit(void);
    6.29 +
    6.30 +/* mode: WSYS_BLOCKING or WSYS_NONBLOCK */
    6.31 +int wsys_process_events(int mode);
    6.32 +
    6.33 +
    6.34 +#endif	/* WSYS_H_ */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/wsys_x11.c	Fri Sep 22 15:26:29 2017 +0300
     7.3 @@ -0,0 +1,298 @@
     7.4 +#include <stdio.h>
     7.5 +#include <stdlib.h>
     7.6 +#include <X11/Xlib.h>
     7.7 +#include <X11/Xutil.h>
     7.8 +#include "wsys.h"
     7.9 +#include "vku.h"
    7.10 +
    7.11 +struct callbacks {
    7.12 +	void (*display)(void);
    7.13 +	void (*reshape)(int, int);
    7.14 +	void (*keyboard)(int, int);
    7.15 +	void (*mouse)(int, int, int, int);
    7.16 +	void (*motion)(int, int);
    7.17 +	void (*passive)(int, int);
    7.18 +};
    7.19 +
    7.20 +enum {
    7.21 +	QUIT = 1,
    7.22 +	RESHAPE = 2,
    7.23 +	REDISPLAY = 4
    7.24 +};
    7.25 +
    7.26 +static void proc_event(XEvent *ev);
    7.27 +
    7.28 +static Display *dpy;
    7.29 +static Window win;
    7.30 +static Atom xa_wm_delete;
    7.31 +static int win_width, win_height;
    7.32 +static int win_mapped;
    7.33 +static unsigned int evmask = StructureNotifyMask | ExposureMask;
    7.34 +static unsigned int pending;
    7.35 +static struct callbacks cb;
    7.36 +
    7.37 +int wsys_create_window(int xsz, int ysz)
    7.38 +{
    7.39 +	int i, scr, num_visuals;
    7.40 +	Window root_win;
    7.41 +	Visual *vis = 0;
    7.42 +	XSetWindowAttributes xattr;
    7.43 +	unsigned int xattr_mask;
    7.44 +	XVisualInfo *vinf, vinf_match;
    7.45 +
    7.46 +	if(!(dpy = XOpenDisplay(0))) {
    7.47 +		fprintf(stderr, "failed to open connection to the X server\n");
    7.48 +		return -1;
    7.49 +	}
    7.50 +	scr = DefaultScreen(dpy);
    7.51 +	root_win = RootWindow(dpy, scr);
    7.52 +
    7.53 +	xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
    7.54 +
    7.55 +	vinf_match.screen = scr;
    7.56 +	vinf_match.depth = 24;
    7.57 +	vinf_match.class = TrueColor;
    7.58 +
    7.59 +	if(!(vinf = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &vinf_match, &num_visuals))) {
    7.60 +		fprintf(stderr, "failed to retrieve matching visuals\n");
    7.61 +		XCloseDisplay(dpy);
    7.62 +		return -1;
    7.63 +	}
    7.64 +
    7.65 +	for(i=0; i<num_visuals; i++) {
    7.66 +		if(vku_xlib_usable_visual(dpy, vinf[i].visualid)) {
    7.67 +			vis = vinf[i].visual;
    7.68 +			break;
    7.69 +		}
    7.70 +	}
    7.71 +	if(!vis) {
    7.72 +		fprintf(stderr, "failed to find approprate visual\n");
    7.73 +		XFree(vinf);
    7.74 +		XCloseDisplay(dpy);
    7.75 +		return -1;
    7.76 +	}
    7.77 +
    7.78 +	xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
    7.79 +	xattr.colormap = XCreateColormap(dpy, root_win, vis, AllocNone);
    7.80 +	xattr_mask = CWBackPixel | CWBorderPixel | CWColormap;
    7.81 +
    7.82 +	if(!(win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, 24, InputOutput, vis, xattr_mask, &xattr))) {
    7.83 +		fprintf(stderr, "failed to create X window\n");
    7.84 +		XFree(vinf);
    7.85 +		XCloseDisplay(dpy);
    7.86 +		return -1;
    7.87 +	}
    7.88 +	XFree(vinf);
    7.89 +
    7.90 +	XSelectInput(dpy, win, evmask);
    7.91 +	XSetWMProtocols(dpy, win, &xa_wm_delete, 1);
    7.92 +
    7.93 +	wsys_set_window_title("X11 window");
    7.94 +	XMapWindow(dpy, win);
    7.95 +
    7.96 +	win_width = xsz;
    7.97 +	win_height = ysz;
    7.98 +	pending = RESHAPE | REDISPLAY;
    7.99 +
   7.100 +	return 0;
   7.101 +}
   7.102 +
   7.103 +void wsys_destroy_window(void)
   7.104 +{
   7.105 +	if(dpy) {
   7.106 +		if(win) {
   7.107 +			XDestroyWindow(dpy, win);
   7.108 +			win = 0;
   7.109 +		}
   7.110 +		XCloseDisplay(dpy);
   7.111 +		dpy = 0;
   7.112 +	}
   7.113 +}
   7.114 +
   7.115 +void wsys_get_window_size(int *xsz, int *ysz)
   7.116 +{
   7.117 +	*xsz = win_width;
   7.118 +	*ysz = win_height;
   7.119 +}
   7.120 +
   7.121 +void wsys_set_window_title(const char *title)
   7.122 +{
   7.123 +	XTextProperty text;
   7.124 +	XStringListToTextProperty((char**)&title, 1, &text);
   7.125 +	XSetWMName(dpy, win, &text);
   7.126 +	XSetWMIconName(dpy, win, &text);
   7.127 +	XFree(text.value);
   7.128 +}
   7.129 +
   7.130 +void wsys_display_callback(void (*func)(void))
   7.131 +{
   7.132 +	cb.display = func;
   7.133 +}
   7.134 +
   7.135 +void wsys_reshape_callback(void (*func)(int, int))
   7.136 +{
   7.137 +	cb.reshape = func;
   7.138 +}
   7.139 +
   7.140 +void wsys_keyboard_callback(void (*func)(int, int))
   7.141 +{
   7.142 +	cb.keyboard = func;
   7.143 +	if(func) {
   7.144 +		evmask |= KeyPressMask | KeyReleaseMask;
   7.145 +	} else {
   7.146 +		evmask &= ~(KeyPressMask | KeyReleaseMask);
   7.147 +	}
   7.148 +	if(win) {
   7.149 +		XSelectInput(dpy, win, evmask);
   7.150 +	}
   7.151 +}
   7.152 +
   7.153 +void wsys_mouse_callback(void (*func)(int, int, int, int))
   7.154 +{
   7.155 +	cb.mouse = func;
   7.156 +	if(func) {
   7.157 +		evmask |= ButtonPressMask | ButtonReleaseMask;
   7.158 +	} else {
   7.159 +		evmask &= ~(ButtonPressMask | ButtonReleaseMask);
   7.160 +	}
   7.161 +	if(win) {
   7.162 +		XSelectInput(dpy, win, evmask);
   7.163 +	}
   7.164 +}
   7.165 +
   7.166 +void wsys_motion_callback(void (*func)(int, int))
   7.167 +{
   7.168 +	cb.motion = func;
   7.169 +	if(func) {
   7.170 +		evmask |= ButtonMotionMask;
   7.171 +	} else {
   7.172 +		evmask &= ~ButtonMotionMask;
   7.173 +	}
   7.174 +	if(win) {
   7.175 +		XSelectInput(dpy, win, evmask);
   7.176 +	}
   7.177 +}
   7.178 +
   7.179 +void wsys_passive_motion_callback(void (*func)(int, int))
   7.180 +{
   7.181 +	cb.passive = func;
   7.182 +	if(func) {
   7.183 +		evmask |= PointerMotionMask;
   7.184 +	} else {
   7.185 +		evmask &= ~PointerMotionMask;
   7.186 +	}
   7.187 +	if(win) {
   7.188 +		XSelectInput(dpy, win, evmask);
   7.189 +	}
   7.190 +}
   7.191 +
   7.192 +void wsys_swap_buffers(void)
   7.193 +{
   7.194 +	/* TODO */
   7.195 +}
   7.196 +
   7.197 +void wsys_redisplay(void)
   7.198 +{
   7.199 +	pending |= REDISPLAY;
   7.200 +}
   7.201 +
   7.202 +void wsys_quit(void)
   7.203 +{
   7.204 +	pending |= QUIT;
   7.205 +}
   7.206 +
   7.207 +int wsys_process_events(int mode)
   7.208 +{
   7.209 +	XEvent xev;
   7.210 +
   7.211 +	if(pending & RESHAPE) {
   7.212 +		if(cb.reshape) {
   7.213 +			cb.reshape(win_width, win_height);
   7.214 +		}
   7.215 +		pending &= ~RESHAPE;
   7.216 +	}
   7.217 +
   7.218 +	if(mode == WSYS_BLOCKING) {
   7.219 +		XNextEvent(dpy, &xev);
   7.220 +		proc_event(&xev);
   7.221 +		if(pending & QUIT) return -1;
   7.222 +	}
   7.223 +
   7.224 +	while(XPending(dpy)) {
   7.225 +		XNextEvent(dpy, &xev);
   7.226 +		proc_event(&xev);
   7.227 +		if(pending & QUIT) return -1;
   7.228 +	}
   7.229 +
   7.230 +	if(pending & REDISPLAY && win_mapped) {
   7.231 +		pending &= ~REDISPLAY;
   7.232 +		if(cb.display) {
   7.233 +			cb.display();
   7.234 +		}
   7.235 +	}
   7.236 +	return 0;
   7.237 +}
   7.238 +
   7.239 +static void proc_event(XEvent *ev)
   7.240 +{
   7.241 +	switch(ev->type) {
   7.242 +	case MapNotify:
   7.243 +		win_mapped = 1;
   7.244 +		break;
   7.245 +
   7.246 +	case UnmapNotify:
   7.247 +		win_mapped = 0;
   7.248 +		break;
   7.249 +
   7.250 +	case ClientMessage:
   7.251 +		if(ev->xclient.data.l[0] == xa_wm_delete) {
   7.252 +			pending |= QUIT;
   7.253 +		}
   7.254 +		break;
   7.255 +
   7.256 +	case ConfigureNotify:
   7.257 +		if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) {
   7.258 +			win_width = ev->xconfigure.width;
   7.259 +			win_height = ev->xconfigure.height;
   7.260 +			pending |= RESHAPE;
   7.261 +		}
   7.262 +		break;
   7.263 +
   7.264 +	case Expose:
   7.265 +		if(ev->xexpose.count == 0) {
   7.266 +			pending |= REDISPLAY;
   7.267 +		}
   7.268 +		break;
   7.269 +
   7.270 +	case KeyPress:
   7.271 +	case KeyRelease:
   7.272 +		if(cb.keyboard) {
   7.273 +			KeySym sym;
   7.274 +			char str[16];
   7.275 +			XLookupString(&ev->xkey, str, sizeof str, &sym, 0);
   7.276 +			cb.keyboard(sym & 0xff, ev->type == KeyPress ? 1 : 0);
   7.277 +		}
   7.278 +		break;
   7.279 +
   7.280 +	case ButtonPress:
   7.281 +	case ButtonRelease:
   7.282 +		if(cb.mouse) {
   7.283 +			int bn = ev->xbutton.button - Button1;
   7.284 +			int pressed = ev->type == ButtonPress ? 1 : 0;
   7.285 +			cb.mouse(bn, pressed, ev->xbutton.x, ev->xbutton.y);
   7.286 +		}
   7.287 +		break;
   7.288 +
   7.289 +	case MotionNotify:
   7.290 +		if(ev->xmotion.state & 0x1f00) {
   7.291 +			if(cb.motion) {
   7.292 +				cb.motion(ev->xmotion.x, ev->xmotion.y);
   7.293 +			}
   7.294 +		} else {
   7.295 +			if(cb.passive) {
   7.296 +				cb.passive(ev->xmotion.x, ev->xmotion.y);
   7.297 +			}
   7.298 +		}
   7.299 +		break;
   7.300 +	}
   7.301 +}