Added swap chain.

This commit is contained in:
2021-06-10 23:47:41 +02:00
parent 02fcf66ef7
commit 9ab1361fbd
7 changed files with 175 additions and 371 deletions

View File

@@ -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)
}

View File

@@ -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
)

View File

@@ -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
View File

@@ -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

View File

@@ -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
View 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
View 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