mirror of
https://github.com/Kugelschieber/vk-experiments.git
synced 2026-01-18 06:40:27 +00:00
Added swap chain.
This commit is contained in:
@@ -1,346 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
module github.com/Kugelschieber/vk-experiments
|
|
||||||
|
|
||||||
go 1.16
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb // indirect
|
|
||||||
github.com/vulkan-go/vulkan v0.0.0-20210402152248-956e3850d8f9 // indirect
|
|
||||||
)
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb h1:T6gaWBvRzJjuOrdCtg8fXXjKai2xSDqWTcKFUPuw8Tw=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/vulkan-go/vulkan v0.0.0-20210402152248-956e3850d8f9 h1:WFujQpkMAAd8dqccEm10n8dly4yQ/R5d2+Us7GutowA=
|
|
||||||
github.com/vulkan-go/vulkan v0.0.0-20210402152248-956e3850d8f9/go.mod h1:Y5Ti1uUBdKDsb0W8aPtIo9krs+29Y7p6Bc9yyy4AM6g=
|
|
||||||
2
run.sh
2
run.sh
@@ -3,12 +3,14 @@
|
|||||||
echo "Building..."
|
echo "Building..."
|
||||||
rm -rf ./build
|
rm -rf ./build
|
||||||
mkdir -p ./build
|
mkdir -p ./build
|
||||||
|
gcc -c src/util.c -o build/util.o || exit
|
||||||
gcc -c src/log.c -o build/log.o || exit
|
gcc -c src/log.c -o build/log.o || exit
|
||||||
gcc `pkg-config --static --libs glfw3` -c src/window.c -o build/window.o || exit
|
gcc `pkg-config --static --libs glfw3` -c src/window.c -o build/window.o || exit
|
||||||
gcc `pkg-config --static --libs glfw3` \
|
gcc `pkg-config --static --libs glfw3` \
|
||||||
`pkg-config --static --libs vulkan` \
|
`pkg-config --static --libs vulkan` \
|
||||||
build/log.o \
|
build/log.o \
|
||||||
build/window.o \
|
build/window.o \
|
||||||
|
build/util.o \
|
||||||
-o main src/main.c || exit
|
-o main src/main.c || exit
|
||||||
echo "Done. Starting app..."
|
echo "Done. Starting app..."
|
||||||
./main
|
./main
|
||||||
|
|||||||
167
src/main.c
167
src/main.c
@@ -1,8 +1,10 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
@@ -10,18 +12,23 @@ typedef struct {
|
|||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
VkPhysicalDevice physicalDevice;
|
VkPhysicalDevice physicalDevice;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
VkQueue graphicsQueue;
|
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
VkQueue graphicsQueue;
|
||||||
|
VkQueue presentQueue;
|
||||||
|
VkSwapchainKHR swapChain;
|
||||||
} VKEContext;
|
} VKEContext;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* title;
|
const char* title;
|
||||||
int validationLayerCount;
|
uint32_t validationLayerCount;
|
||||||
const char** validationLayers;
|
const char** validationLayers;
|
||||||
|
uint32_t deviceExtensionCount;
|
||||||
|
const char** deviceExtensions;
|
||||||
} VKEConfig;
|
} VKEConfig;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t graphicsQueueFamily;
|
uint32_t graphicsQueueFamily;
|
||||||
|
uint32_t presentQueueFamily;
|
||||||
} VKEQueueFamilyIndices;
|
} VKEQueueFamilyIndices;
|
||||||
|
|
||||||
bool vkeCheckValidationLayerSupport(const char** validationLayers, int n) {
|
bool vkeCheckValidationLayerSupport(const char** validationLayers, int n) {
|
||||||
@@ -97,12 +104,21 @@ int vkeFindQueueFamilies(VKEContext* ctx, VKEQueueFamilyIndices* indices) {
|
|||||||
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
|
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(ctx->physicalDevice, &queueFamilyCount, queueFamilies);
|
vkGetPhysicalDeviceQueueFamilyProperties(ctx->physicalDevice, &queueFamilyCount, queueFamilies);
|
||||||
bool foundGraphicsQueue = false;
|
bool foundGraphicsQueue = false;
|
||||||
|
bool foundPresentQueue = false;
|
||||||
|
|
||||||
for(int i = 0; i < queueFamilyCount; i++) {
|
for(int i = 0; i < queueFamilyCount; i++) {
|
||||||
if(queueFamilies[i].queueFlags&VK_QUEUE_GRAPHICS_BIT) {
|
if(queueFamilies[i].queueFlags&VK_QUEUE_GRAPHICS_BIT) {
|
||||||
indices->graphicsQueueFamily = i;
|
indices->graphicsQueueFamily = i;
|
||||||
foundGraphicsQueue = true;
|
foundGraphicsQueue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkBool32 presentSupport = false;
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(ctx->physicalDevice, i, ctx->surface, &presentSupport);
|
||||||
|
|
||||||
|
if(presentSupport) {
|
||||||
|
indices->presentQueueFamily = i;
|
||||||
|
foundPresentQueue = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!foundGraphicsQueue) {
|
if(!foundGraphicsQueue) {
|
||||||
@@ -110,24 +126,38 @@ int vkeFindQueueFamilies(VKEContext* ctx, VKEQueueFamilyIndices* indices) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!foundPresentQueue) {
|
||||||
|
vkeLogError("present queue family index not found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vkeCreateLogicalDeviceAndQueues(VKEContext* ctx, VKEConfig* config, VKEQueueFamilyIndices* queueFamilies) {
|
int vkeCreateLogicalDeviceAndQueues(VKEContext* ctx, VKEConfig* config, VKEQueueFamilyIndices* queueFamilies) {
|
||||||
VkDeviceQueueCreateInfo queueCreateInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
|
||||||
.queueFamilyIndex = queueFamilies->graphicsQueueFamily,
|
|
||||||
.queueCount = 1
|
|
||||||
};
|
|
||||||
float queuePriority = 1.0f;
|
float queuePriority = 1.0f;
|
||||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
VkDeviceQueueCreateInfo queueCreateInfo[] = {
|
||||||
|
{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||||
|
.queueFamilyIndex = queueFamilies->graphicsQueueFamily,
|
||||||
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &queuePriority
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||||
|
.queueFamilyIndex = queueFamilies->presentQueueFamily,
|
||||||
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &queuePriority
|
||||||
|
}
|
||||||
|
};
|
||||||
//VkPhysicalDeviceFeatures deviceFeatures; TODO
|
//VkPhysicalDeviceFeatures deviceFeatures; TODO
|
||||||
VkDeviceCreateInfo createInfo = {
|
VkDeviceCreateInfo createInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||||
.pQueueCreateInfos = &queueCreateInfo,
|
.pQueueCreateInfos = queueCreateInfo,
|
||||||
.queueCreateInfoCount = 1,
|
.queueCreateInfoCount = 2,
|
||||||
.pEnabledFeatures = VK_NULL_HANDLE,
|
.pEnabledFeatures = VK_NULL_HANDLE,
|
||||||
.enabledExtensionCount = 0
|
.enabledExtensionCount = config->deviceExtensionCount,
|
||||||
|
.ppEnabledExtensionNames = config->deviceExtensions
|
||||||
};
|
};
|
||||||
|
|
||||||
if(config->validationLayerCount > 0) {
|
if(config->validationLayerCount > 0) {
|
||||||
@@ -143,6 +173,107 @@ int vkeCreateLogicalDeviceAndQueues(VKEContext* ctx, VKEConfig* config, VKEQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
vkGetDeviceQueue(ctx->device, queueFamilies->graphicsQueueFamily, 0, &ctx->graphicsQueue);
|
vkGetDeviceQueue(ctx->device, queueFamilies->graphicsQueueFamily, 0, &ctx->graphicsQueue);
|
||||||
|
vkGetDeviceQueue(ctx->device, queueFamilies->presentQueueFamily, 0, &ctx->presentQueue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vkeCreateSwapChain(VKEContext* ctx, VKEQueueFamilyIndices* queueFamilies, GLFWwindow* window) {
|
||||||
|
// collect surface capabilities
|
||||||
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->physicalDevice, ctx->surface, &capabilities);
|
||||||
|
uint32_t formatCount;
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->physicalDevice, ctx->surface, &formatCount, NULL);
|
||||||
|
uint32_t presentModeCount;
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->physicalDevice, ctx->surface, &presentModeCount, NULL);
|
||||||
|
|
||||||
|
if(formatCount == 0) {
|
||||||
|
vkeLogError("no color formats available");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(presentModeCount == 0) {
|
||||||
|
vkeLogError("no present modes available");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR formats[formatCount];
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->physicalDevice, ctx->surface, &formatCount, formats);
|
||||||
|
VkPresentModeKHR presentModes[presentModeCount];
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->physicalDevice, ctx->surface, &presentModeCount, presentModes);
|
||||||
|
|
||||||
|
// select the color format
|
||||||
|
VkSurfaceFormatKHR format = formats[0];
|
||||||
|
|
||||||
|
for(int i = 0; i < formatCount; i++) {
|
||||||
|
if(formats[i].format == VK_FORMAT_B8G8R8A8_SRGB && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||||
|
format = formats[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// select present mode
|
||||||
|
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
|
||||||
|
for(int i = 0; i < presentModeCount; i++) {
|
||||||
|
if(presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||||
|
presentMode = presentModes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// choose extent
|
||||||
|
VkExtent2D extent;
|
||||||
|
|
||||||
|
if(capabilities.currentExtent.width != UINT32_MAX) {
|
||||||
|
extent = capabilities.currentExtent;
|
||||||
|
} else {
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
VkExtent2D actualExtent = {width, height};
|
||||||
|
actualExtent.width = max(capabilities.minImageExtent.width, min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||||
|
actualExtent.height = max(capabilities.minImageExtent.height, min(capabilities.maxImageExtent.height, actualExtent.height));
|
||||||
|
extent = actualExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// select the image count
|
||||||
|
uint32_t imageCount = capabilities.minImageCount + 1;
|
||||||
|
|
||||||
|
if(capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) {
|
||||||
|
imageCount = capabilities.maxImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the swap chain
|
||||||
|
VkSwapchainCreateInfoKHR createInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||||
|
.surface = ctx->surface,
|
||||||
|
.minImageCount = imageCount,
|
||||||
|
.imageFormat = format.format,
|
||||||
|
.imageColorSpace = format.colorSpace,
|
||||||
|
.imageExtent = extent,
|
||||||
|
.imageArrayLayers = 1,
|
||||||
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||||
|
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||||
|
.preTransform = capabilities.currentTransform,
|
||||||
|
.presentMode = presentMode,
|
||||||
|
.clipped = VK_TRUE,
|
||||||
|
.oldSwapchain = VK_NULL_HANDLE
|
||||||
|
};
|
||||||
|
|
||||||
|
if(queueFamilies->graphicsQueueFamily != queueFamilies->presentQueueFamily) {
|
||||||
|
const uint32_t indices[] = {queueFamilies->graphicsQueueFamily, queueFamilies->presentQueueFamily};
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
createInfo.queueFamilyIndexCount = 2;
|
||||||
|
createInfo.pQueueFamilyIndices = indices;
|
||||||
|
} else {
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
createInfo.queueFamilyIndexCount = 0;
|
||||||
|
createInfo.pQueueFamilyIndices = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(vkCreateSwapchainKHR(ctx->device, &createInfo, NULL, &ctx->swapChain) != VK_SUCCESS) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +316,10 @@ int vkeInit(VKEContext* ctx, VKEConfig* config, GLFWwindow* window) {
|
|||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(vkeCreateWindowSurface(ctx->instance, window, &ctx->surface) != 0) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
VKEQueueFamilyIndices queueFamilies;
|
VKEQueueFamilyIndices queueFamilies;
|
||||||
|
|
||||||
if(vkeFindQueueFamilies(ctx, &queueFamilies) != 0) {
|
if(vkeFindQueueFamilies(ctx, &queueFamilies) != 0) {
|
||||||
@@ -195,7 +330,7 @@ int vkeInit(VKEContext* ctx, VKEConfig* config, GLFWwindow* window) {
|
|||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vkeCreateWindowSurface(ctx->instance, window, &ctx->surface) != 0) {
|
if(vkeCreateSwapChain(ctx, &queueFamilies, window) != 0) {
|
||||||
return -6;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +338,7 @@ int vkeInit(VKEContext* ctx, VKEConfig* config, GLFWwindow* window) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vkeDestroy(VKEContext* ctx) {
|
void vkeDestroy(VKEContext* ctx) {
|
||||||
|
vkDestroySwapchainKHR(ctx->device, ctx->swapChain, NULL);
|
||||||
vkDestroySurfaceKHR(ctx->instance, ctx->surface, NULL);
|
vkDestroySurfaceKHR(ctx->instance, ctx->surface, NULL);
|
||||||
vkDestroyDevice(ctx->device, NULL);
|
vkDestroyDevice(ctx->device, NULL);
|
||||||
vkDestroyInstance(ctx->instance, NULL);
|
vkDestroyInstance(ctx->instance, NULL);
|
||||||
@@ -228,10 +364,15 @@ int main(int argc, const char *argv[]) {
|
|||||||
const char* validationLayers[] = {
|
const char* validationLayers[] = {
|
||||||
"VK_LAYER_KHRONOS_validation"
|
"VK_LAYER_KHRONOS_validation"
|
||||||
};
|
};
|
||||||
|
const char* deviceExtensions[] = {
|
||||||
|
"VK_KHR_swapchain"
|
||||||
|
};
|
||||||
VKEConfig config = {
|
VKEConfig config = {
|
||||||
.title = title,
|
.title = title,
|
||||||
.validationLayerCount = 1,
|
.validationLayerCount = 1,
|
||||||
.validationLayers = validationLayers
|
.validationLayers = validationLayers,
|
||||||
|
.deviceExtensionCount = 1,
|
||||||
|
.deviceExtensions = deviceExtensions
|
||||||
};
|
};
|
||||||
|
|
||||||
if(vkeInit(&ctx, &config, window) != 0) {
|
if(vkeInit(&ctx, &config, window) != 0) {
|
||||||
|
|||||||
9
src/util.c
Normal file
9
src/util.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int min(int a, int b) {
|
||||||
|
return a > b ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int max(int a, int b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
10
src/util.h
Normal file
10
src/util.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef VKE_UTIL_H
|
||||||
|
#define VKE_UTIL_H
|
||||||
|
|
||||||
|
// Returns the smaller value of the parameters.
|
||||||
|
int min(int a, int b);
|
||||||
|
|
||||||
|
// Returns the bigger value of the parameters.
|
||||||
|
int max(int a, int b);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user