diff --git a/01_Simple_Sprite/main.go b/01_Simple_Sprite/main.go deleted file mode 100644 index 1570575..0000000 --- a/01_Simple_Sprite/main.go +++ /dev/null @@ -1,294 +0,0 @@ -package main - -import ( - "errors" - "github.com/go-gl/glfw/v3.3/glfw" - vk "github.com/vulkan-go/vulkan" - "log" - "runtime" -) - -var ( - vkInstance vk.Instance - vkPhysicalDevice vk.PhysicalDevice - vkDevice vk.Device - vkGraphicsQueue vk.Queue - vkPresentQueue vk.Queue - vkSurface vk.Surface - vkSwapchain vk.Swapchain - vkSwapchainImages []vk.Image - vkSwapchainImageViews []vk.ImageView -) - -func init() { - runtime.LockOSThread() -} - -func createWindow(title string, width, height int) (*glfw.Window, error) { - if err := glfw.Init(); err != nil { - return nil, err - } - - if !glfw.VulkanSupported() { - return nil, errors.New("missing required Vulkan support") - } - - window, err := glfw.CreateWindow(width, height, title, nil, nil) - - if err != nil { - return nil, err - } - - window.MakeContextCurrent() - return window, nil -} - -func destroyWindow(window *glfw.Window) { - window.Destroy() - glfw.Terminate() -} - -func initVk(window *glfw.Window, width, height uint32) error { - log.Println("Initializing Vulkan...") - vk.SetGetInstanceProcAddr(glfw.GetVulkanGetInstanceProcAddress()) - - if err := vk.Init(); err != nil { - return err - } - - // create Vulkan instance - extensions := window.GetRequiredInstanceExtensions() - result := vk.CreateInstance(&vk.InstanceCreateInfo{ - SType: vk.StructureTypeInstanceCreateInfo, - PApplicationInfo: &vk.ApplicationInfo{ - SType: vk.StructureTypeApplicationInfo, - PApplicationName: "01 Simple Sprite", - ApiVersion: vk.ApiVersion11, - }, - EnabledExtensionCount: uint32(len(extensions)), - PpEnabledExtensionNames: extensions, - }, nil, &vkInstance) - - if result != vk.Success { - return errors.New("error creating Vulkan instance") - } - - // create surface - surface, err := window.CreateWindowSurface(vkInstance, nil) - - if err != nil { - return errors.New("error creating Vulkan surface") - } - - vkSurface = vk.SurfaceFromPointer(surface) - - // select the first device with Vulkan support - var deviceCount uint32 - - if result := vk.EnumeratePhysicalDevices(vkInstance, &deviceCount, nil); result != vk.Success { - return errors.New("error counting Vulkan devices") - } - - if deviceCount == 0 { - return errors.New("no device with Vulkan support found") - } - - devices := make([]vk.PhysicalDevice, 1) - - if result := vk.EnumeratePhysicalDevices(vkInstance, &deviceCount, devices); result != vk.Success { - return errors.New("error listing Vulkan devices") - } - - for _, d := range devices { - // TODO check suitability - vkPhysicalDevice = d - break - } - - if vkPhysicalDevice == nil { - return errors.New("no suitable Vulkan device found") - } - - // find a graphics queue - var queueCount uint32 - vk.GetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueCount, nil) - queueProperties := make([]vk.QueueFamilyProperties, queueCount) - vk.GetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueCount, queueProperties) - var graphicsQueueIndex, presentQueueIndex uint32 - foundGraphicsQueue, foundPresentQueue := false, false - - for i, q := range queueProperties { - if !foundGraphicsQueue && vk.QueueFlagBits(q.QueueFlags)&vk.QueueGraphicsBit == 1 { - graphicsQueueIndex = uint32(i) - foundGraphicsQueue = true - - if foundPresentQueue { - break - } - } - - if !foundPresentQueue { - var presentSupport vk.Bool32 - vk.GetPhysicalDeviceSurfaceSupport(vkPhysicalDevice, uint32(i), vkSurface, &presentSupport) - - if presentSupport == 1 { - presentQueueIndex = uint32(i) - foundPresentQueue = true - - if foundGraphicsQueue { - break - } - } - } - } - - if !foundGraphicsQueue { - return errors.New("no Vulkan graphics queue found") - } - - if !foundPresentQueue { - return errors.New("no Vulkan present queue found") - } - - // create a logical device and queues - queues := []vk.DeviceQueueCreateInfo{ - { - SType: vk.StructureTypeDeviceQueueCreateInfo, - QueueFamilyIndex: graphicsQueueIndex, - QueueCount: 1, - PQueuePriorities: []float32{1}, - }, - } - - result = vk.CreateDevice(vkPhysicalDevice, &vk.DeviceCreateInfo{ - SType: vk.StructureTypeDeviceCreateInfo, - QueueCreateInfoCount: 1, - PQueueCreateInfos: queues, - EnabledExtensionCount: 1, - PpEnabledExtensionNames: []string{ - vk.KhrDisplaySwapchainExtensionName, - }, - }, nil, &vkDevice) - - if result != vk.Success { - return errors.New("error creating logical Vulkan device") - } - - vk.GetDeviceQueue(vkDevice, graphicsQueueIndex, 0, &vkGraphicsQueue) - vk.GetDeviceQueue(vkDevice, presentQueueIndex, 0, &vkPresentQueue) - - // create swap chain (screen buffer) and get the images - sharingMode := vk.SharingModeExclusive - queueFamilyIndexCount := 0 - var queueFamilyIndices []uint32 - - if graphicsQueueIndex != presentQueueIndex { - sharingMode = vk.SharingModeConcurrent - queueFamilyIndexCount = 2 - queueFamilyIndices = []uint32{graphicsQueueIndex, presentQueueIndex} - } - - result = vk.CreateSwapchain(vkDevice, &vk.SwapchainCreateInfo{ - SType: vk.StructureTypeSwapchainCreateInfo, - Surface: vkSurface, - MinImageCount: uint32(3), - ImageFormat: vk.FormatB8g8r8a8Uint, - ImageColorSpace: vk.ColorspaceSrgbNonlinear, - ImageExtent: vk.Extent2D{Width: width, Height: height}, - ImageArrayLayers: 1, - ImageUsage: vk.ImageUsageFlags(vk.ImageUsageColorAttachmentBit), - ImageSharingMode: sharingMode, - QueueFamilyIndexCount: uint32(queueFamilyIndexCount), - PQueueFamilyIndices: queueFamilyIndices, - //PreTransform - CompositeAlpha: vk.CompositeAlphaOpaqueBit, - PresentMode: vk.PresentModeMailbox, - Clipped: vk.True, - OldSwapchain: vk.NullSwapchain, - }, nil, &vkSwapchain) - - if result != vk.Success { - return errors.New("error creating Vulkan swap chain") - } - - var imgCount uint32 - vk.GetSwapchainImages(vkDevice, vkSwapchain, &imgCount, nil) - result = vk.GetSwapchainImages(vkDevice, vkSwapchain, &imgCount, vkSwapchainImages) - - if result != vk.Success { - return errors.New("error getting Vulkan swap chain images") - } - - // create image views for the swap chain images - vkSwapchainImageViews = make([]vk.ImageView, 0, imgCount) - - for i, img := range vkSwapchainImages { - result = vk.CreateImageView(vkDevice, &vk.ImageViewCreateInfo{ - SType: vk.StructureTypeImageViewCreateInfo, - Image: img, - ViewType: vk.ImageViewType2d, - Format: vk.FormatB8g8r8a8Uint, - Components: vk.ComponentMapping{ - R: vk.ComponentSwizzleR, - G: vk.ComponentSwizzleG, - B: vk.ComponentSwizzleB, - A: vk.ComponentSwizzleA, - }, - SubresourceRange: vk.ImageSubresourceRange{ - AspectMask: vk.ImageAspectFlags(vk.ImageAspectColorBit), - BaseMipLevel: uint32(0), - LevelCount: uint32(1), - BaseArrayLayer: uint32(0), - LayerCount: uint32(1), - }, - }, nil, &vkSwapchainImageViews[i]) - - if result != vk.Success { - return errors.New("error creating swap chain image view") - } - } - - log.Println("Done initializing Vulkan...") - return nil -} - -func cleanupVk() { - for _, img := range vkSwapchainImageViews { - vk.DestroyImageView(vkDevice, img, nil) - } - - vk.DestroySwapchain(vkDevice, vkSwapchain, nil) - vk.DestroySurface(vkInstance, vkSurface, nil) - vk.DestroyDevice(vkDevice, nil) - vk.DestroyInstance(vkInstance, nil) -} - -func load() { - -} - -func loop(window *glfw.Window) { - for !window.ShouldClose() { - // ... - window.SwapBuffers() - glfw.PollEvents() - } -} - -func main() { - window, err := createWindow("01 Simple Sprite", 640, 480) - - if err != nil { - log.Fatalf("error creating window: %s", err) - } - - defer destroyWindow(window) - - if err := initVk(window, 640, 480); err != nil { - log.Fatalf("error initializing Vulkan: %s", err) - } - - defer cleanupVk() - load() - loop(window) -} diff --git a/README.md b/README.md index 99ab2bc..eafd984 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Golang Vulkan Experiments -Learning and experimenting with Vulkan using Golang. +Learning and experimenting with Vulkan using C. diff --git a/_go/01_Triangle/main.go b/_go/01_Triangle/main.go new file mode 100644 index 0000000..4f9c20e --- /dev/null +++ b/_go/01_Triangle/main.go @@ -0,0 +1,346 @@ +package main + +import ( + "errors" + "fmt" + "github.com/go-gl/glfw/v3.3/glfw" + vk "github.com/vulkan-go/vulkan" + "log" + "runtime" +) + +var ( + vkInstance vk.Instance + vkPhysicalDevice vk.PhysicalDevice + vkDevice vk.Device + vkGraphicsQueue vk.Queue + vkPresentQueue vk.Queue + vkSurface vk.Surface + vkSwapchain vk.Swapchain + vkSwapchainImages []vk.Image + vkSwapchainImageViews []vk.ImageView +) + +func init() { + runtime.LockOSThread() +} + +func createWindow(title string, width, height int) (*glfw.Window, error) { + if err := glfw.Init(); err != nil { + return nil, err + } + + if !glfw.VulkanSupported() { + return nil, errors.New("vulkan not support") + } + + glfw.WindowHint(glfw.ClientAPI, glfw.NoAPI) + window, err := glfw.CreateWindow(width, height, title, nil, nil) + + if err != nil { + return nil, err + } + + window.SetSizeLimits(width, height, width, height) + return window, nil +} + +func destroyWindow(window *glfw.Window) { + window.Destroy() + glfw.Terminate() +} + +func initVk(window *glfw.Window, width, height uint32) error { + log.Println("Initializing vulkan...") + vk.SetGetInstanceProcAddr(glfw.GetVulkanGetInstanceProcAddress()) + + if err := vk.Init(); err != nil { + return err + } + + // create vulkan instance + extensions := window.GetRequiredInstanceExtensions() + + if result := vk.CreateInstance(&vk.InstanceCreateInfo{ + SType: vk.StructureTypeInstanceCreateInfo, + PApplicationInfo: &vk.ApplicationInfo{ + SType: vk.StructureTypeApplicationInfo, + PApplicationName: "01 Triangle", + ApiVersion: vk.ApiVersion11, + }, + EnabledExtensionCount: uint32(len(extensions)), + PpEnabledExtensionNames: extensions, + }, nil, &vkInstance); result != vk.Success { + return errors.New(fmt.Sprintf("vulkan: error creating instance: %d", result)) + } + + // create surface + surface, err := window.CreateWindowSurface(vkInstance, nil) + + if err != nil { + return errors.New(fmt.Sprintf("vulkan: error creating surface: %s", err)) + } + + vkSurface = vk.SurfaceFromPointer(surface) + + // select the first device with vulkan support + var deviceCount uint32 + + if result := vk.EnumeratePhysicalDevices(vkInstance, &deviceCount, nil); result != vk.Success { + return errors.New(fmt.Sprintf("vulkan: error counting devices: %d", result)) + } + + if deviceCount == 0 { + return errors.New("vulkan: no device with vulkan support found") + } + + log.Printf("vulkan: number of physical devices: %d", deviceCount) + devices := make([]vk.PhysicalDevice, deviceCount) + + if result := vk.EnumeratePhysicalDevices(vkInstance, &deviceCount, devices); result != vk.Success { + return errors.New(fmt.Sprintf("vulkan: error listing devices: %d", result)) + } + + for _, d := range devices { + vkPhysicalDevice = d + break // TODO check suitability + } + + if vkPhysicalDevice == nil { + return errors.New("vulkan: no suitable device found") + } + + // find a graphics and presentation queue + var queueCount uint32 + vk.GetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueCount, nil) + queueProperties := make([]vk.QueueFamilyProperties, queueCount) + vk.GetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueCount, queueProperties) + var presentQueueIndex, graphicsQueueIndex uint32 + foundPresentQueue, foundGraphicsQueue := false, false + + for i := range queueProperties { + queueProperties[i].Deref() + + if !foundPresentQueue { + var presentSupport vk.Bool32 + vk.GetPhysicalDeviceSurfaceSupport(vkPhysicalDevice, uint32(i), vkSurface, &presentSupport) + + if presentSupport == 1 { + presentQueueIndex = uint32(i) + foundPresentQueue = true + + if foundGraphicsQueue { + break + } + } + } + + if !foundGraphicsQueue && queueProperties[i].QueueFlags&vk.QueueFlags(vk.QueueGraphicsBit) != 0 { + graphicsQueueIndex = uint32(i) + foundGraphicsQueue = true + + if foundPresentQueue { + break + } + } + } + + if !foundPresentQueue { + return errors.New("vulkan: no present queue found") + } + + if !foundGraphicsQueue { + return errors.New("vulkan: no graphics queue found") + } + + // create a logical device and queues + queues := []vk.DeviceQueueCreateInfo{ + { + SType: vk.StructureTypeDeviceQueueCreateInfo, + QueueFamilyIndex: graphicsQueueIndex, + QueueCount: 1, + PQueuePriorities: []float32{1}, + }, + } + + if result := vk.CreateDevice(vkPhysicalDevice, &vk.DeviceCreateInfo{ + SType: vk.StructureTypeDeviceCreateInfo, + QueueCreateInfoCount: 1, + PQueueCreateInfos: queues, + }, nil, &vkDevice); result != vk.Success { + return errors.New(fmt.Sprintf("vulkan: error creating logical device: %d", result)) + } + + vk.GetDeviceQueue(vkDevice, graphicsQueueIndex, 0, &vkGraphicsQueue) + vk.GetDeviceQueue(vkDevice, presentQueueIndex, 0, &vkPresentQueue) + + // create swap chain + var surfaceCapabilities vk.SurfaceCapabilities + + if result := vk.GetPhysicalDeviceSurfaceCapabilities(vkPhysicalDevice, vkSurface, &surfaceCapabilities); result != vk.Success { + return errors.New(fmt.Sprintf("vulkan: error reading device surface capabilities: %d", result)) + } + + surfaceCapabilities.Deref() + var swapchainFormatCount uint32 + vk.GetPhysicalDeviceSurfaceFormats(vkPhysicalDevice, vkSurface, &swapchainFormatCount, nil) + + if swapchainFormatCount == 0 { + return errors.New("vulkan: no surface formats present") + } + + formats := make([]vk.SurfaceFormat, swapchainFormatCount) + vk.GetPhysicalDeviceSurfaceFormats(vkPhysicalDevice, vkSurface, &swapchainFormatCount, formats) + var swapchainFormat vk.SurfaceFormat + + for i := range formats { + formats[i].Deref() + swapchainFormat = formats[i] + break // TODO + } + + desiredSwapchainImages := surfaceCapabilities.MinImageCount + 1 + + if surfaceCapabilities.MaxImageCount > 0 && desiredSwapchainImages > surfaceCapabilities.MaxImageCount { + desiredSwapchainImages = surfaceCapabilities.MaxImageCount + } + + var swapchainPreTransform vk.SurfaceTransformFlagBits + requiredTransforms := vk.SurfaceTransformIdentityBit + supportedTransforms := surfaceCapabilities.SupportedTransforms + + if vk.SurfaceTransformFlagBits(supportedTransforms)&requiredTransforms != 0 { + swapchainPreTransform = requiredTransforms + } else { + swapchainPreTransform = surfaceCapabilities.CurrentTransform + } + + swapchainCompositeAlpha := vk.CompositeAlphaOpaqueBit + swapchainCompositeAlphaFlags := []vk.CompositeAlphaFlagBits{ + vk.CompositeAlphaOpaqueBit, + vk.CompositeAlphaPreMultipliedBit, + vk.CompositeAlphaPostMultipliedBit, + vk.CompositeAlphaInheritBit, + } + + for i := range swapchainCompositeAlphaFlags { + alphaFlags := vk.CompositeAlphaFlags(swapchainCompositeAlphaFlags[i]) + + if surfaceCapabilities.SupportedCompositeAlpha&alphaFlags != 0 { + swapchainCompositeAlpha = swapchainCompositeAlphaFlags[i] + break + } + } + + surfaceCapabilities.CurrentExtent.Deref() + var swapchainSize vk.Extent2D + + if surfaceCapabilities.CurrentExtent.Width == vk.MaxUint32 { + swapchainSize.Width = width + swapchainSize.Height = height + } else { + swapchainSize = surfaceCapabilities.CurrentExtent + } + + if result := vk.CreateSwapchain(vkDevice, &vk.SwapchainCreateInfo{ + SType: vk.StructureTypeSwapchainCreateInfo, + Surface: vkSurface, + MinImageCount: desiredSwapchainImages, + ImageFormat: swapchainFormat.Format, + ImageColorSpace: swapchainFormat.ColorSpace, + ImageExtent: vk.Extent2D{ + Width: swapchainSize.Width, + Height: swapchainSize.Height, + }, + ImageArrayLayers: 1, + ImageUsage: vk.ImageUsageFlags(vk.ImageUsageColorAttachmentBit), + ImageSharingMode: vk.SharingModeExclusive, + PreTransform: swapchainPreTransform, + CompositeAlpha: swapchainCompositeAlpha, + PresentMode: vk.PresentModeFifo, + Clipped: vk.True, + OldSwapchain: vk.NullSwapchain, + }, nil, &vkSwapchain); result != vk.Success { + return errors.New(fmt.Sprintf("error creating vulkan swap chain: %d", result)) + } + + /*var imgCount uint32 + vk.GetSwapchainImages(vkDevice, vkSwapchain, &imgCount, nil) + result = vk.GetSwapchainImages(vkDevice, vkSwapchain, &imgCount, vkSwapchainImages) + + if result != vk.Success { + return errors.New("error getting vulkan swap chain images") + } + + // create image views for the swap chain images + vkSwapchainImageViews = make([]vk.ImageView, 0, imgCount) + + for i, img := range vkSwapchainImages { + result = vk.CreateImageView(vkDevice, &vk.ImageViewCreateInfo{ + SType: vk.StructureTypeImageViewCreateInfo, + Image: img, + ViewType: vk.ImageViewType2d, + Format: vk.FormatB8g8r8a8Uint, + Components: vk.ComponentMapping{ + R: vk.ComponentSwizzleR, + G: vk.ComponentSwizzleG, + B: vk.ComponentSwizzleB, + A: vk.ComponentSwizzleA, + }, + SubresourceRange: vk.ImageSubresourceRange{ + AspectMask: vk.ImageAspectFlags(vk.ImageAspectColorBit), + BaseMipLevel: uint32(0), + LevelCount: uint32(1), + BaseArrayLayer: uint32(0), + LayerCount: uint32(1), + }, + }, nil, &vkSwapchainImageViews[i]) + + if result != vk.Success { + return errors.New("error creating swap chain image view") + } + }*/ + + log.Println("Done initializing vulkan...") + return nil +} + +func cleanupVk() { + /*for _, img := range vkSwapchainImageViews { + vk.DestroyImageView(vkDevice, img, nil) + } + + vk.DestroySwapchain(vkDevice, vkSwapchain, nil)*/ + vk.DestroyDevice(vkDevice, nil) + vk.DestroySurface(vkInstance, vkSurface, nil) + vk.DestroyInstance(vkInstance, nil) +} + +func load() { + +} + +func loop(window *glfw.Window) { + for !window.ShouldClose() { + // ... + glfw.PollEvents() + } +} + +func main() { + window, err := createWindow("01 Triangle", 640, 480) + + if err != nil { + log.Fatalf("error creating window: %s", err) + } + + defer destroyWindow(window) + + if err := initVk(window, 640, 480); err != nil { + log.Fatalf("error initializing vulkan: %s", err) + } + + defer cleanupVk() + load() + loop(window) +} diff --git a/go.mod b/_go/go.mod similarity index 100% rename from go.mod rename to _go/go.mod diff --git a/go.sum b/_go/go.sum similarity index 100% rename from go.sum rename to _go/go.sum