Mercurial > games > semicongine
comparison src/engine.nim @ 461:59d861a6a5c4
add: initial version
author | Sam <sam@basx.dev> |
---|---|
date | Wed, 14 Dec 2022 00:49:35 +0700 |
parents | |
children | bb2a7d3a7003 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 461:59d861a6a5c4 |
---|---|
1 import std/enumerate | |
2 | |
3 import ./vulkan | |
4 import ./vulkan_helpers | |
5 import ./xlib_helpers | |
6 | |
7 import ./glslang/glslang | |
8 import ./glslang/glslang_c_shader_types | |
9 | |
10 | |
11 import | |
12 x11/xlib, | |
13 x11/x | |
14 | |
15 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32) | |
16 | |
17 type | |
18 QueueFamily = object | |
19 properties*: VkQueueFamilyProperties | |
20 hasSurfaceSupport*: bool | |
21 PhyscialDevice = object | |
22 device*: VkPhysicalDevice | |
23 extensions*: seq[string] | |
24 properties*: VkPhysicalDeviceProperties | |
25 features*: VkPhysicalDeviceFeatures | |
26 queueFamilies*: seq[QueueFamily] | |
27 surfaceCapabilities*: VkSurfaceCapabilitiesKHR | |
28 surfaceFormats: seq[VkSurfaceFormatKHR] | |
29 presentModes: seq[VkPresentModeKHR] | |
30 Vulkan* = object | |
31 instance*: VkInstance | |
32 deviceList*: seq[PhyscialDevice] | |
33 activePhysicalDevice*: PhyscialDevice | |
34 activeQueueFamily*: uint32 | |
35 device*: VkDevice | |
36 presentationQueue*: VkQueue | |
37 surface*: VkSurfaceKHR | |
38 selectedSurfaceFormat: VkSurfaceFormatKHR | |
39 selectedPresentationMode: VkPresentModeKHR | |
40 selectedExtent: VkExtent2D | |
41 swapChain: VkSwapchainKHR | |
42 swapImages: seq[VkImage] | |
43 swapImageViews: seq[VkImageView] | |
44 Engine* = object | |
45 display*: PDisplay | |
46 window*: x.Window | |
47 vulkan*: Vulkan | |
48 | |
49 | |
50 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhyscialDevice] = | |
51 for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance): | |
52 var device = PhyscialDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice)) | |
53 vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties)) | |
54 vkGetPhysicalDeviceFeatures(vulkanPhysicalDevice, addr(device.features)) | |
55 checkVkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkanPhysicalDevice, surface, addr(device.surfaceCapabilities)) | |
56 device.surfaceFormats = getDeviceSurfaceFormats(vulkanPhysicalDevice, surface) | |
57 device.presentModes = getDeviceSurfacePresentModes(vulkanPhysicalDevice, surface) | |
58 | |
59 for i, queueFamilyProperty in enumerate(getQueueFamilies(vulkanPhysicalDevice)): | |
60 var hasSurfaceSupport: VkBool32 = VkBool32(false) | |
61 checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, uint32(i), surface, addr(hasSurfaceSupport)) | |
62 device.queueFamilies.add(QueueFamily(properties: queueFamilyProperty, hasSurfaceSupport: bool(hasSurfaceSupport))) | |
63 | |
64 result.add(device) | |
65 | |
66 proc filterForDevice(devices: seq[PhyscialDevice]): seq[(PhyscialDevice, uint32)] = | |
67 for device in devices: | |
68 if "VK_KHR_swapchain" in device.extensions: | |
69 for i, queueFamily in enumerate(device.queueFamilies): | |
70 let hasGraphics = bool(uint32(queueFamily.properties.queueFlags) and ord(VK_QUEUE_GRAPHICS_BIT)) | |
71 if ( | |
72 queueFamily.hasSurfaceSupport and | |
73 hasGraphics and | |
74 device.surfaceFormats.len > 0 and | |
75 device.presentModes.len > 0 | |
76 ): | |
77 result.add((device, uint32(i))) | |
78 | |
79 proc filterForSurfaceFormat(formats: seq[VkSurfaceFormatKHR]): seq[VkSurfaceFormatKHR] = | |
80 for format in formats: | |
81 if format.format == VK_FORMAT_B8G8R8A8_SRGB and format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: | |
82 result.add(format) | |
83 | |
84 proc getSwapExtent(display: PDisplay, window: Window, capabilities: VkSurfaceCapabilitiesKHR): VkExtent2D = | |
85 if capabilities.currentExtent.width != high(uint32): | |
86 return capabilities.currentExtent | |
87 else: | |
88 let (width, height) = xlibFramebufferSize(display, window) | |
89 return VkExtent2D( | |
90 width: min(max(uint32(width), capabilities.minImageExtent.width), capabilities.maxImageExtent.width), | |
91 height: min(max(uint32(height), capabilities.minImageExtent.height), capabilities.maxImageExtent.height), | |
92 ) | |
93 | |
94 proc igniteEngine*(): Engine = | |
95 vkLoad1_0() | |
96 vkLoad1_1() | |
97 vkLoad1_2() | |
98 | |
99 # init X11 window | |
100 (result.display, result.window) = xlibInit() | |
101 | |
102 # create vulkan instance | |
103 result.vulkan.instance = createVulkanInstance(VULKAN_VERSION) | |
104 | |
105 # create vulkan-X11 surface | |
106 var surfaceCreateInfo = VkXlibSurfaceCreateInfoKHR( | |
107 sType: VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, | |
108 dpy: result.display, | |
109 window: result.window, | |
110 ) | |
111 checkVkResult vkCreateXlibSurfaceKHR(result.vulkan.instance, addr(surfaceCreateInfo), nil, addr(result.vulkan.surface)) | |
112 | |
113 # determine device and queue to use and instantiate | |
114 result.vulkan.deviceList = result.vulkan.instance.getAllPhysicalDevices(result.vulkan.surface) | |
115 let usableDevices = result.vulkan.deviceList.filterForDevice() | |
116 if len(usableDevices) == 0: | |
117 raise newException(Exception, "No suitable graphics device found") | |
118 (result.vulkan.activePhysicalDevice, result.vulkan.activeQueueFamily) = usableDevices[0] | |
119 | |
120 (result.vulkan.device, result.vulkan.presentationQueue) = getVulcanDevice( | |
121 result.vulkan.activePhysicalDevice.device, | |
122 result.vulkan.activePhysicalDevice.features, | |
123 result.vulkan.activeQueueFamily | |
124 ) | |
125 | |
126 # determine surface format for swapchain | |
127 let usableSurfaceFormats = filterForSurfaceFormat(result.vulkan.activePhysicalDevice.surfaceFormats) | |
128 if len(usableSurfaceFormats) == 0: | |
129 raise newException(Exception, "No suitable surface formats found") | |
130 result.vulkan.selectedSurfaceFormat = usableSurfaceFormats[0] | |
131 result.vulkan.selectedPresentationMode = getPresentMode(result.vulkan.activePhysicalDevice.presentModes) | |
132 result.vulkan.selectedExtent = getSwapExtent(result.display, result.window, result.vulkan.activePhysicalDevice.surfaceCapabilities) | |
133 | |
134 # setup swapchain | |
135 var swapchainCreateInfo = VkSwapchainCreateInfoKHR( | |
136 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, | |
137 surface: result.vulkan.surface, | |
138 minImageCount: max(result.vulkan.activePhysicalDevice.surfaceCapabilities.minImageCount + 1, result.vulkan.activePhysicalDevice.surfaceCapabilities.maxImageCount), | |
139 imageFormat: result.vulkan.selectedSurfaceFormat.format, | |
140 imageColorSpace: result.vulkan.selectedSurfaceFormat.colorSpace, | |
141 imageExtent: result.vulkan.selectedExtent, | |
142 imageArrayLayers: 1, | |
143 imageUsage: VkImageUsageFlags(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), | |
144 # VK_SHARING_MODE_CONCURRENT no supported (i.e cannot use different queue families for drawing to swap surface?) | |
145 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, | |
146 preTransform: result.vulkan.activePhysicalDevice.surfaceCapabilities.currentTransform, | |
147 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, | |
148 presentMode: result.vulkan.selectedPresentationMode, | |
149 clipped: VkBool32(true), | |
150 oldSwapchain: VkSwapchainKHR(0), | |
151 ) | |
152 checkVkResult vkCreateSwapchainKHR(result.vulkan.device, addr(swapchainCreateInfo), nil, addr(result.vulkan.swapChain)) | |
153 result.vulkan.swapImages = getSwapChainImages(result.vulkan.device, result.vulkan.swapChain) | |
154 | |
155 # setup swapchian image views | |
156 result.vulkan.swapImageViews = newSeq[VkImageView](result.vulkan.swapImages.len) | |
157 for i, image in enumerate(result.vulkan.swapImages): | |
158 var imageViewCreateInfo = VkImageViewCreateInfo( | |
159 sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | |
160 image: image, | |
161 viewType: VK_IMAGE_VIEW_TYPE_2D, | |
162 format: result.vulkan.selectedSurfaceFormat.format, | |
163 components: VkComponentMapping( | |
164 r: VK_COMPONENT_SWIZZLE_IDENTITY, | |
165 g: VK_COMPONENT_SWIZZLE_IDENTITY, | |
166 b: VK_COMPONENT_SWIZZLE_IDENTITY, | |
167 a: VK_COMPONENT_SWIZZLE_IDENTITY, | |
168 ), | |
169 subresourceRange: VkImageSubresourceRange( | |
170 aspectMask: VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT), | |
171 baseMipLevel: 0, | |
172 levelCount: 1, | |
173 baseArrayLayer: 0, | |
174 layerCount: 1, | |
175 ), | |
176 ) | |
177 checkVkResult vkCreateImageView(result.vulkan.device, addr(imageViewCreateInfo), nil, addr(result.vulkan.swapImageViews[i])) | |
178 echo compileShaderToSPIRV_Vulkan(GLSLANG_STAGE_VERTEX, """#version 450 | |
179 vec2 positions[3] = vec2[]( | |
180 vec2(0.0, -0.5), | |
181 vec2(0.5, 0.5), | |
182 vec2(-0.5, 0.5) | |
183 ); | |
184 void main() { | |
185 gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); | |
186 }""", "<memory-shader>") | |
187 | |
188 | |
189 proc fullThrottle*(engine: Engine) = | |
190 var event: XEvent | |
191 while true: | |
192 discard XNextEvent(engine.display, addr(event)) | |
193 case event.theType | |
194 of Expose: | |
195 discard | |
196 of ClientMessage: | |
197 if cast[Atom](event.xclient.data.l[0]) == deleteMessage: | |
198 break | |
199 of KeyPress: | |
200 let key = XLookupKeysym(cast[PXKeyEvent](addr(event)), 0) | |
201 if key != 0: | |
202 echo "Key ", key, " pressed" | |
203 of ButtonPressMask: | |
204 echo "Mouse button ", event.xbutton.button, " pressed at ", | |
205 event.xbutton.x, ",", event.xbutton.y | |
206 else: | |
207 discard | |
208 | |
209 proc trash*(engine: Engine) = | |
210 vkDestroySwapchainKHR(engine.vulkan.device, engine.vulkan.swapChain, nil); | |
211 vkDestroySurfaceKHR(engine.vulkan.instance, engine.vulkan.surface, nil); | |
212 vkDestroyDevice(engine.vulkan.device, nil) | |
213 vkDestroyInstance(engine.vulkan.instance, nil) | |
214 checkXlibResult engine.display.XDestroyWindow(engine.window) | |
215 discard engine.display.XCloseDisplay() # always returns 0 |