Mercurial > games > semicongine
comparison src/engine.nim @ 0:5daf3f236d87
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 | 0:5daf3f236d87 |
|---|---|
| 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 |
