Mercurial > games > semicongine
comparison svk/api.nim @ 1489:e6bd1f553c1b default tip main
add: quite a bit more wrapper
author | sam <sam@basx.dev> |
---|---|
date | Sun, 18 May 2025 23:47:16 +0700 |
parents | 3ce7c132fdac |
children |
comparison
equal
deleted
inserted
replaced
1488:3ce7c132fdac | 1489:e6bd1f553c1b |
---|---|
5 import std/logging | 5 import std/logging |
6 import std/os | 6 import std/os |
7 | 7 |
8 include ./vkapi | 8 include ./vkapi |
9 | 9 |
10 const VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 3, 0) | 10 # ============================================================================= |
11 # UTILS ======================================================================= | |
12 # ============================================================================= | |
13 | |
14 if not defined(release): | |
15 addHandler(newConsoleLogger()) | |
16 addHandler(newFileLogger("svk.log")) | |
17 | |
18 # log level | |
19 when defined(release): | |
20 const LOGLEVEL {.strdefine.}: string = "Warn" | |
21 else: | |
22 const LOGLEVEL {.strdefine.}: string = "Debug" | |
23 setLogFilter(parseEnum[Level]("lvl" & LOGLEVEL)) | |
24 | |
25 template debugAssert(arg: untyped): untyped = | |
26 when not defined(release): | |
27 assert arg | |
28 | |
29 # we will support vulkan 1.2 for maximum portability | |
30 const VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 2, 0) | |
11 | 31 |
12 iterator items*[T: HoleyEnum](E: typedesc[T]): T = | 32 iterator items*[T: HoleyEnum](E: typedesc[T]): T = |
13 for a in enumFullRange(E): | 33 for a in enumFullRange(E): |
14 yield a | 34 yield a |
15 | 35 |
27 error "Vulkan error: ", astToStr(call), " returned ", $value | 47 error "Vulkan error: ", astToStr(call), " returned ", $value |
28 raise newException( | 48 raise newException( |
29 Exception, "Vulkan error: " & astToStr(call) & " returned " & $value | 49 Exception, "Vulkan error: " & astToStr(call) & " returned " & $value |
30 ) | 50 ) |
31 | 51 |
52 # ============================================================================= | |
53 # PLATFORM TYPES ============================================================== | |
54 # ============================================================================= | |
55 | |
56 when defined(windows): | |
57 type NativeWindow* = object | |
58 hinstance*: HINSTANCE | |
59 hwnd*: HWND | |
60 g_wpPrev*: WINDOWPLACEMENT | |
61 else: | |
62 type NativeWindow* = object | |
63 display*: ptr Display | |
64 window*: Window | |
65 emptyCursor*: Cursor | |
66 ic*: XIC | |
67 | |
68 | |
69 | |
70 | |
71 # ============================================================================= | |
72 # VULKAN INSTANCE ============================================================= | |
73 # ============================================================================= | |
74 | |
32 type SVkInstance* = object | 75 type SVkInstance* = object |
33 vkInstance: VkInstance | 76 vkInstance: VkInstance |
34 debugMessenger: VkDebugUtilsMessengerEXT | 77 debugMessenger: VkDebugUtilsMessengerEXT |
78 window: NativeWindow | |
79 vkSurface*: VkSurfaceKHR | |
80 | |
81 proc createWindow(title: string): NativeWindow | |
35 | 82 |
36 proc `=copy`(a: var SVkInstance, b: SVkInstance) {.error.} | 83 proc `=copy`(a: var SVkInstance, b: SVkInstance) {.error.} |
37 | 84 |
38 proc `=destroy`(a: SVkInstance) = | 85 proc `=destroy`(a: SVkInstance) = |
86 debugAssert a.vkInstance.pointer == nil | |
87 debugAssert a.vkSurface.pointer == nil | |
88 debugAssert a.debugMessenger.pointer == nil | |
89 | |
90 proc destroy*(a: var SVkInstance) = | |
39 if a.vkInstance.pointer != nil: | 91 if a.vkInstance.pointer != nil: |
40 if a.debugMessenger.pointer != nil: | 92 if a.debugMessenger.pointer != nil: |
41 vkDestroyDebugUtilsMessengerEXT(a.vkInstance, a.debugMessenger, nil) | 93 vkDestroyDebugUtilsMessengerEXT(a.vkInstance, a.debugMessenger, nil) |
94 a.debugMessenger = VkDebugUtilsMessengerEXT(nil) | |
95 vkDestroySurfaceKHR(a.vkInstance, a.vkSurface, nil) | |
96 a.vkSurface = VkSurfaceKHR(nil) | |
42 a.vkInstance.vkDestroyInstance(nil) | 97 a.vkInstance.vkDestroyInstance(nil) |
98 a.vkInstance = VkInstance(nil) | |
43 | 99 |
44 proc debugCallback( | 100 proc debugCallback( |
45 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, | 101 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, |
46 messageTypes: VkDebugUtilsMessageTypeFlagsEXT, | 102 messageTypes: VkDebugUtilsMessageTypeFlagsEXT, |
47 pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, | 103 pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, |
51 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: lvlDebug, | 107 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: lvlDebug, |
52 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: lvlInfo, | 108 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: lvlInfo, |
53 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: lvlWarn, | 109 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: lvlWarn, |
54 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: lvlError, | 110 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: lvlError, |
55 }.toTable | 111 }.toTable |
56 log LOG_LEVEL_MAPPING[messageSeverity] | 112 log LOG_LEVEL_MAPPING[messageSeverity], "SVK-LOG: ", $pCallbackData.pMessage |
57 if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: | 113 if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: |
58 # stderr.write getStackTrace() | |
59 # stderr.writeLine LOG_LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}" | |
60 let errorMsg = $pCallbackData.pMessage & ": " & getStackTrace() | 114 let errorMsg = $pCallbackData.pMessage & ": " & getStackTrace() |
61 raise newException(Exception, errorMsg) | 115 raise newException(Exception, errorMsg) |
62 return VK_FALSE | 116 return VK_FALSE |
63 | 117 |
64 proc svkCreateInstance*( | 118 proc svkCreateInstance*( |
65 applicationName: string, | 119 applicationName: string, |
66 enabledLayers: openArray[string] = [], | 120 enabledLayers: openArray[string] = [], |
67 enabledExtensions: openArray[string] = | 121 enabledExtensions: openArray[string] = |
68 if defined(release): | 122 if defined(release): |
69 @["VK_KHR_surface"] | 123 if defined(windows): |
124 @["VK_KHR_surface", "VK_KHR_win32_surface"] | |
125 else: | |
126 @["VK_KHR_surface", "VK_KHR_xlib_surface"] | |
70 else: | 127 else: |
71 @["VK_KHR_surface", "VK_EXT_debug_utils"], | 128 if defined(windows): |
129 @["VK_KHR_surface", "VK_EXT_debug_utils", "VK_KHR_win32_surface"] | |
130 else: | |
131 @["VK_KHR_surface", "VK_EXT_debug_utils", "VK_KHR_xlib_surface"], | |
72 engineName = "semicongine", | 132 engineName = "semicongine", |
73 withSwapchain = true, | |
74 ): SVkInstance = | 133 ): SVkInstance = |
75 putEnv("VK_LOADER_LAYERS_ENABLE", "*validation") | 134 putEnv("VK_LOADER_LAYERS_ENABLE", "*validation") |
76 putEnv( | 135 putEnv( |
77 "VK_LAYER_ENABLES", | 136 "VK_LAYER_ENABLES", |
78 "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", | 137 "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", |
79 ) | 138 ) |
80 initVulkanLoader() | 139 initVulkanLoader() |
81 | 140 |
141 var allLayers = @enabledLayers | |
142 when not defined(release): | |
143 allLayers.add "VK_LAYER_KHRONOS_validation" | |
144 | |
82 let | 145 let |
83 appinfo = VkApplicationInfo( | 146 appinfo = VkApplicationInfo( |
84 pApplicationName: applicationName, | 147 pApplicationName: applicationName, |
85 pEngineName: engineName, | 148 pEngineName: engineName, |
86 apiVersion: VULKAN_VERSION, | 149 apiVersion: VULKAN_VERSION, |
87 ) | 150 ) |
88 enabledLayersC = allocCStringArray(enabledLayers) | 151 enabledLayersC = allocCStringArray(allLayers) |
89 enabledExtensionsC = allocCStringArray(enabledExtensions) | 152 enabledExtensionsC = allocCStringArray(enabledExtensions) |
90 createinfo = VkInstanceCreateInfo( | 153 createinfo = VkInstanceCreateInfo( |
91 pApplicationInfo: addr appinfo, | 154 pApplicationInfo: addr appinfo, |
92 enabledLayerCount: enabledLayers.len.uint32, | 155 enabledLayerCount: allLayers.len.uint32, |
93 ppEnabledLayerNames: enabledLayersC, | 156 ppEnabledLayerNames: enabledLayersC, |
94 enabledExtensionCount: enabledExtensions.len.uint32, | 157 enabledExtensionCount: enabledExtensions.len.uint32, |
95 ppEnabledExtensionNames: enabledExtensionsC, | 158 ppEnabledExtensionNames: enabledExtensionsC, |
96 ) | 159 ) |
97 checkVkResult vkCreateInstance(addr createinfo, nil, addr result.vkInstance) | 160 checkVkResult vkCreateInstance(addr createinfo, nil, addr result.vkInstance) |
98 | 161 |
99 enabledLayersC.deallocCStringArray() | 162 enabledLayersC.deallocCStringArray() |
100 enabledExtensionsC.deallocCStringArray() | 163 enabledExtensionsC.deallocCStringArray() |
101 | 164 |
165 # only support up to vulkan 1.2 for maximum portability | |
102 load_VK_VERSION_1_0(result.vkInstance) | 166 load_VK_VERSION_1_0(result.vkInstance) |
103 load_VK_VERSION_1_1(result.vkInstance) | 167 load_VK_VERSION_1_1(result.vkInstance) |
104 load_VK_VERSION_1_2(result.vkInstance) | 168 load_VK_VERSION_1_2(result.vkInstance) |
105 load_VK_VERSION_1_3(result.vkInstance) | |
106 | 169 |
107 for extension in enabledExtensions: | 170 for extension in enabledExtensions: |
108 loadExtension(result.vkInstance, extension) | 171 loadExtension(result.vkInstance, extension) |
109 if withSwapchain: | 172 load_VK_KHR_swapchain(result.vkInstance) |
110 load_VK_KHR_swapchain(result.vkInstance) | 173 |
111 | 174 var allTypes: VkDebugUtilsMessageTypeFlagsEXT |
175 for t in VkDebugUtilsMessageTypeFlagBitsEXT: | |
176 allTypes = allTypes or t | |
112 when not defined(release): | 177 when not defined(release): |
113 var debugMessengerCreateInfo = VkDebugUtilsMessengerCreateInfoEXT( | 178 var debugMessengerCreateInfo = VkDebugUtilsMessengerCreateInfoEXT( |
114 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT.items.toSeq, | 179 messageSeverity: VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, |
115 messageType: VkDebugUtilsMessageTypeFlagBitsEXT.items.toSeq, | 180 messageType: VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT or VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, |
116 pfnUserCallback: debugCallback, | 181 pfnUserCallback: debugCallback, |
117 ) | 182 ) |
118 checkVkResult vkCreateDebugUtilsMessengerEXT( | 183 checkVkResult vkCreateDebugUtilsMessengerEXT( |
119 result.vkInstance, addr debugMessengerCreateInfo, nil, addr result.debugMessenger | 184 result.vkInstance, addr debugMessengerCreateInfo, nil, addr result.debugMessenger |
120 ) | 185 ) |
186 | |
187 | |
188 result.window = createWindow(applicationName) | |
189 when defined(windows): | |
190 var surfaceCreateInfo = VkWin32SurfaceCreateInfoKHR(hinstance: window.hinstance, hwnd: window.hwnd) | |
191 checkVkResult vkCreateWin32SurfaceKHR(instance, addr surfaceCreateInfo, nil, addr result.vkSurface) | |
192 else: | |
193 var surfaceCreateInfo = VkXlibSurfaceCreateInfoKHR(dpy: result.window.display, window: result.window.window) | |
194 checkVkResult result.vkInstance.vkCreateXlibSurfaceKHR(addr surfaceCreateInfo, nil, addr result.vkSurface) | |
195 | |
196 | |
197 | |
198 # ============================================================================= | |
199 # PHYSICAL DEVICES ============================================================ | |
200 # ============================================================================= | |
201 | |
202 type | |
203 SVkMemoryType* = object | |
204 size: uint64 | |
205 deviceLocal: bool # fast for gpu access | |
206 hostCached: bool # fast for host access | |
207 hostVisible: bool # can use vkMapMemory | |
208 hostCohorent: bool # does *not* require vkFlushMappedMemoryRanges and vkInvalidateMappedMemoryRanges | |
209 SVkQueueFamilies* = object | |
210 count: int | |
211 hasGraphics: bool # implies "hasTransfer" | |
212 hasCompute: bool # implies "hasTransfer" | |
213 | |
214 SVkPhysicalDevice* = object | |
215 name*: string | |
216 vkPhysicalDevice*: VkPhysicalDevice | |
217 vkPhysicalDeviceFeatures*: VkPhysicalDeviceFeatures | |
218 vkPhysicalDeviceProperties*: VkPhysicalDeviceProperties | |
219 memoryTypes*: seq[SVkMemoryType] | |
220 queueFamily*: uint32 | |
221 | |
222 proc getUsablePhysicalDevices*(instance: SVkInstance): seq[SVkPhysicalDevice] = | |
223 var nDevices: uint32 | |
224 checkVkResult instance.vkInstance.vkEnumeratePhysicalDevices(addr nDevices, nil) | |
225 var devices = newSeq[VkPhysicalDevice](nDevices) | |
226 checkVkResult instance.vkInstance.vkEnumeratePhysicalDevices(addr nDevices, addr devices[0]) | |
227 for d in devices: | |
228 var dev = SVkPhysicalDevice(vkPhysicalDevice: d) | |
229 d.vkGetPhysicalDeviceFeatures(addr dev.vkPhysicalDeviceFeatures) | |
230 d.vkGetPhysicalDeviceProperties(addr dev.vkPhysicalDeviceProperties) | |
231 | |
232 if dev.vkPhysicalDeviceProperties.deviceType notin [VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU]: | |
233 continue | |
234 dev.name = $cast[cstring](addr dev.vkPhysicalDeviceProperties.deviceName[0]) | |
235 | |
236 var memoryProperties: VkPhysicalDeviceMemoryProperties | |
237 d.vkGetPhysicalDeviceMemoryProperties(addr memoryProperties) | |
238 for i in 0 ..< memoryProperties.memoryTypeCount: | |
239 let heapI = memoryProperties.memoryTypes[i].heapIndex | |
240 dev.memoryTypes.add SVkMemoryType( | |
241 size: memoryProperties.memoryHeaps[heapI].size.uint64, | |
242 deviceLocal: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
243 hostCached: VK_MEMORY_PROPERTY_HOST_CACHED_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
244 hostVisible: VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
245 hostCohorent: VK_MEMORY_PROPERTY_HOST_COHERENT_BIT in memoryProperties.memoryTypes[i].propertyFlags, | |
246 ) | |
247 | |
248 | |
249 var familyQueueCount: uint32 | |
250 var vkQueueFamilyProperties: seq[VkQueueFamilyProperties] | |
251 d.vkGetPhysicalDeviceQueueFamilyProperties(addr familyQueueCount, nil) | |
252 vkQueueFamilyProperties.setLen(familyQueueCount) | |
253 d.vkGetPhysicalDeviceQueueFamilyProperties(addr familyQueueCount, addr vkQueueFamilyProperties[0]) | |
254 dev.queueFamily = high(uint32) | |
255 for i in 0 ..< familyQueueCount: | |
256 let hasGraphics = VK_QUEUE_GRAPHICS_BIT in vkQueueFamilyProperties[i].queueFlags | |
257 let hasCompute = VK_QUEUE_COMPUTE_BIT in vkQueueFamilyProperties[i].queueFlags | |
258 let hasPresentation = VK_FALSE | |
259 checkVkResult dev.vkPhysicalDevice.vkGetPhysicalDeviceSurfaceSupportKHR(i, instance.vkSurface, addr hasPresentation) | |
260 | |
261 if hasGraphics and hasCompute and bool(hasPresentation): | |
262 dev.queueFamily = i | |
263 break | |
264 if dev.queueFamily == high(uint32): | |
265 raise newException(Exception, "Did not find queue family with graphics and compute support!") | |
266 | |
267 result.add dev | |
268 | |
269 when defined(windows): | |
270 proc createWindow(title: string): NativeWindow = | |
271 result.hInstance = HINSTANCE(GetModuleHandle(nil)) | |
272 var | |
273 windowClassName = T"EngineWindowClass" | |
274 windowName = T(title) | |
275 windowClass = WNDCLASSEX( | |
276 cbSize: UINT(WNDCLASSEX.sizeof), | |
277 lpfnWndProc: windowHandler, | |
278 hInstance: result.hInstance, | |
279 lpszClassName: windowClassName, | |
280 hcursor: currentCursor, | |
281 ) | |
282 | |
283 if (RegisterClassEx(addr(windowClass)) == 0): | |
284 raise newException(Exception, "Unable to register window class") | |
285 | |
286 result.hwnd = CreateWindowEx( | |
287 DWORD(0), | |
288 windowClassName, | |
289 windowName, | |
290 DWORD(WS_OVERLAPPEDWINDOW), | |
291 CW_USEDEFAULT, | |
292 CW_USEDEFAULT, | |
293 CW_USEDEFAULT, | |
294 CW_USEDEFAULT, | |
295 HMENU(0), | |
296 HINSTANCE(0), | |
297 result.hInstance, | |
298 nil, | |
299 ) | |
300 | |
301 result.g_wpPrev.length = UINT(sizeof(WINDOWPLACEMENT)) | |
302 discard result.hwnd.ShowWindow(SW_SHOW) | |
303 discard result.hwnd.SetForegroundWindow() | |
304 discard result.hwnd.SetFocus() | |
305 | |
306 proc destroyWindow*(window: NativeWindow) = | |
307 DestroyWindow(window.hwnd) | |
308 | |
309 else: | |
310 import ../semicongine/thirdparty/x11/xkblib | |
311 import ../semicongine/thirdparty/x11/xutil | |
312 | |
313 var deleteMessage* {.hint[GlobalVar]: off.}: x.Atom # one internal use, not serious | |
314 | |
315 proc XErrorLogger(display: PDisplay, event: PXErrorEvent): cint {.cdecl.} = | |
316 logging.error "Xlib: " & $event[] | |
317 | |
318 proc createWindow(title: string): NativeWindow = | |
319 doAssert XInitThreads() != 0 | |
320 let display = XOpenDisplay(nil) | |
321 if display == nil: | |
322 quit "Failed to open display" | |
323 discard XSetErrorHandler(XErrorLogger) | |
324 | |
325 let screen = display.XDefaultScreen() | |
326 let rootWindow = display.XRootWindow(screen) | |
327 let vis = display.XDefaultVisual(screen) | |
328 discard display.XkbSetDetectableAutoRepeat(true, nil) | |
329 var | |
330 attribs: XWindowAttributes | |
331 width = cuint(800) | |
332 height = cuint(600) | |
333 doAssert display.XGetWindowAttributes(rootWindow, addr(attribs)) != 0 | |
334 | |
335 var attrs = XSetWindowAttributes( | |
336 event_mask: | |
337 FocusChangeMask or KeyPressMask or KeyReleaseMask or ExposureMask or | |
338 VisibilityChangeMask or StructureNotifyMask or ButtonMotionMask or ButtonPressMask or | |
339 ButtonReleaseMask | |
340 ) | |
341 let window = display.XCreateWindow( | |
342 rootWindow, | |
343 (attribs.width - cint(width)) div 2, | |
344 (attribs.height - cint(height)) div 2, | |
345 width, | |
346 height, | |
347 0, | |
348 display.XDefaultDepth(screen), | |
349 InputOutput, | |
350 vis, | |
351 CWEventMask, | |
352 addr(attrs), | |
353 ) | |
354 doAssert display.XSetStandardProperties(window, title, "window", 0, nil, 0, nil) != 0 | |
355 # get an input context, to allow encoding of key-events to characters | |
356 | |
357 let im = XOpenIM(display, nil, nil, nil) | |
358 assert im != nil | |
359 let ic = im.XCreateIC(XNInputStyle, XIMPreeditNothing or XIMStatusNothing, nil) | |
360 assert ic != nil | |
361 | |
362 doAssert display.XMapWindow(window) != 0 | |
363 | |
364 deleteMessage = display.XInternAtom("WM_DELETE_WINDOW", XBool(false)) | |
365 doAssert display.XSetWMProtocols(window, addr(deleteMessage), 1) != 0 | |
366 | |
367 var data = "\0".cstring | |
368 var pixmap = display.XCreateBitmapFromData(window, data, 1, 1) | |
369 var color: XColor | |
370 var empty_cursor = | |
371 display.XCreatePixmapCursor(pixmap, pixmap, addr(color), addr(color), 0, 0) | |
372 doAssert display.XFreePixmap(pixmap) != 0 | |
373 | |
374 discard display.XSync(0) | |
375 | |
376 # wait until window is shown | |
377 var ev: XEvent | |
378 while ev.theType != MapNotify: | |
379 discard display.XNextEvent(addr(ev)) | |
380 | |
381 result = NativeWindow(display: display, window: window, emptyCursor: empty_cursor, ic: ic) | |
382 | |
383 proc destroyWindow*(window: NativeWindow) = | |
384 doAssert XDestroyWindow(window.display, window.window) != 0 | |
385 |