Red screen?
Initalised vulkan for rendering bar some validation errors Added core types, platform detection and util macros
This commit is contained in:
15
code/core/macros.h
Normal file
15
code/core/macros.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#if !defined(LD_CORE_MACROS_H_)
|
||||
#define LD_CORE_MACROS_H_
|
||||
|
||||
#define ArraySize(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define Min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define Max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define _Glue(a, b) a##b
|
||||
#define _Stringify(x) #x
|
||||
|
||||
#define Glue(a, b) _Glue(a, b)
|
||||
#define Stringify(x) _Stringify(x)
|
||||
|
||||
|
||||
#endif // LD_CORE_MACROS_H_
|
||||
73
code/core/platform.h
Normal file
73
code/core/platform.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#if !defined(LD_CORE_PLATFORM_H_)
|
||||
#define LD_CORE_PLATFORM_H_
|
||||
|
||||
#if !defined(LD_RELEASE)
|
||||
#define LD_RELEASE 0
|
||||
#endif
|
||||
|
||||
// -- Operating system
|
||||
|
||||
#define OS_WINDOWS 0
|
||||
#define OS_LINUX 0
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef OS_WINDOWS
|
||||
#define OS_WINDOWS 1
|
||||
#elif defined(__linux__)
|
||||
#undef OS_LINUX
|
||||
#define OS_LINUX 1
|
||||
#else
|
||||
#error "unsupported operating system"
|
||||
#endif
|
||||
|
||||
// -- Architecture
|
||||
|
||||
#define ARCH_AMD64 0
|
||||
|
||||
#if defined(__amd64__) || defined(_M_AMD64)
|
||||
#undef ARCH_AMD64
|
||||
#define ARCH_AMD64 1
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
|
||||
// -- Compiler
|
||||
|
||||
#define COMPILER_CLANG 0
|
||||
#define COMPILER_CL 0
|
||||
#define COMPILER_GCC 0
|
||||
|
||||
#if defined(__clang__)
|
||||
#undef COMPILER_CLANG
|
||||
#define COMPILER_CLANG 1
|
||||
#elif defined(_MSC_VER)
|
||||
#undef COMPILER_CL
|
||||
#define COMPILER_CL 1
|
||||
#elif defined(__GNUC__)
|
||||
#undef COMPILER_GCC
|
||||
#define COMPILER_GCC 1
|
||||
#else
|
||||
#error "unsupported compiler"
|
||||
#endif
|
||||
|
||||
// -- Language
|
||||
|
||||
#define LANG_C 0
|
||||
#define LANG_CPP 0
|
||||
|
||||
#if defined(__OBJC__)
|
||||
#error "unuspported language"
|
||||
#elif defined(__cplusplus)
|
||||
#undef LANG_CPP
|
||||
#define LANG_CPP 1
|
||||
#else
|
||||
#undef LANG_C
|
||||
#define LANG_C 1
|
||||
#endif
|
||||
|
||||
#if OS_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#endif // LD_CORE_PLATFORM_H_
|
||||
32
code/core/types.h
Normal file
32
code/core/types.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#if !defined(LD_CORE_TYPES_H_)
|
||||
#define LD_CORE_TYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <float.h>
|
||||
|
||||
typedef uint8_t U8;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef uint64_t U64;
|
||||
|
||||
typedef int8_t S8;
|
||||
typedef int16_t S16;
|
||||
typedef int32_t S32;
|
||||
typedef int64_t S64;
|
||||
|
||||
typedef int8_t B8;
|
||||
typedef int16_t B16;
|
||||
typedef int32_t B32;
|
||||
typedef int64_t B64;
|
||||
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
|
||||
typedef struct Str8 Str8;
|
||||
struct Str8 {
|
||||
S64 count;
|
||||
U8 *data;
|
||||
};
|
||||
|
||||
#endif // LD_CORE_TYPES_H_
|
||||
88
code/first.c
88
code/first.c
@@ -2,7 +2,16 @@
|
||||
#include <stdbool.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "core/types.h"
|
||||
#include "core/platform.h"
|
||||
#include "core/macros.h"
|
||||
|
||||
#include "vulkan/core.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
printf("[Error] :: Failed to initialise SDL3 (%s)\n", SDL_GetError());
|
||||
return 1;
|
||||
@@ -14,12 +23,89 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vk_Setup(window);
|
||||
|
||||
bool running = true;
|
||||
while (running) {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_EVENT_QUIT) { running = false; }
|
||||
}
|
||||
|
||||
int w, h;
|
||||
SDL_GetWindowSizeInPixels(window, &w, &h);
|
||||
|
||||
Vk_Frame *frame = Vk_FrameBegin(window);
|
||||
VkCommandBuffer cmd = frame->cmd;
|
||||
|
||||
VkImageMemoryBarrier2 colour_optimal = { 0 };
|
||||
colour_optimal.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||
colour_optimal.srcStageMask = VK_PIPELINE_STAGE_2_NONE;
|
||||
colour_optimal.srcAccessMask = VK_ACCESS_2_NONE;
|
||||
colour_optimal.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
colour_optimal.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
colour_optimal.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
colour_optimal.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
colour_optimal.image = vk.swapchain.images[frame->image];
|
||||
|
||||
colour_optimal.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
colour_optimal.subresourceRange.layerCount = 1;
|
||||
colour_optimal.subresourceRange.levelCount = 1;
|
||||
|
||||
VkDependencyInfo colour_barrier = { 0 };
|
||||
colour_barrier.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
||||
colour_barrier.imageMemoryBarrierCount = 1;
|
||||
colour_barrier.pImageMemoryBarriers = &colour_optimal;
|
||||
|
||||
vk.CmdPipelineBarrier2(cmd, &colour_barrier);
|
||||
|
||||
VkClearValue clear_colour;
|
||||
clear_colour.color.float32[0] = 1.0f;
|
||||
clear_colour.color.float32[1] = 0.0f;
|
||||
clear_colour.color.float32[2] = 0.0f;
|
||||
clear_colour.color.float32[3] = 1.0f;
|
||||
|
||||
VkRenderingAttachmentInfo colour_attachment = { 0 };
|
||||
colour_attachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
|
||||
colour_attachment.imageView = vk.swapchain.views[frame->image];
|
||||
colour_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
colour_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
colour_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colour_attachment.clearValue = clear_colour;
|
||||
|
||||
VkRenderingInfo rendering_info = { 0 };
|
||||
rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
|
||||
rendering_info.renderArea = (VkRect2D) { 0, 0, w, h };
|
||||
rendering_info.layerCount = 1;
|
||||
rendering_info.colorAttachmentCount = 1;
|
||||
rendering_info.pColorAttachments = &colour_attachment;
|
||||
|
||||
vk.CmdBeginRendering(cmd, &rendering_info);
|
||||
|
||||
vk.CmdEndRendering(cmd);
|
||||
|
||||
VkImageMemoryBarrier2 present_src = { 0 };
|
||||
present_src.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||
present_src.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
present_src.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
present_src.dstStageMask = VK_PIPELINE_STAGE_2_NONE;
|
||||
present_src.dstAccessMask = VK_ACCESS_2_NONE;
|
||||
present_src.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
present_src.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
present_src.image = vk.swapchain.images[frame->image];
|
||||
|
||||
present_src.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
present_src.subresourceRange.layerCount = 1;
|
||||
present_src.subresourceRange.levelCount = 1;
|
||||
|
||||
VkDependencyInfo to_present = { 0 };
|
||||
to_present.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
||||
to_present.imageMemoryBarrierCount = 1;
|
||||
to_present.pImageMemoryBarriers = &present_src;
|
||||
|
||||
vk.CmdPipelineBarrier2(cmd, &to_present);
|
||||
|
||||
Vk_FrameEnd();
|
||||
}
|
||||
|
||||
SDL_DestroyWindow(window);
|
||||
@@ -27,3 +113,5 @@ int main(int argc, char **argv) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "vulkan/core.c"
|
||||
|
||||
364
code/vulkan/core.c
Normal file
364
code/vulkan/core.c
Normal file
@@ -0,0 +1,364 @@
|
||||
#if OS_WINDOWS
|
||||
|
||||
#define VK_PLATFORM_SURFACE_EXTENSION VK_KHR_WIN32_SURFACE_EXTENSION_NAME
|
||||
|
||||
static void *Vk_LoadLibrary() {
|
||||
void *result = LoadLibraryA("vulkan-1.dll");
|
||||
|
||||
if (result != 0) {
|
||||
vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(result, "vkGetInstanceProcAddr");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Vk_CreateSurface(SDL_Window *window) {
|
||||
SDL_PropertiesID prop_id = SDL_GetWindowProperties(window);
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR create_info = { 0 };
|
||||
create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
create_info.hinstance = SDL_GetPointerProperty(prop_id, SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER, 0);
|
||||
create_info.hwnd = SDL_GetPointerProperty(prop_id, SDL_PROP_WINDOW_WIN32_HWND_POINTER, 0);
|
||||
|
||||
vk.err = vk.CreateWin32SurfaceKHR(vk.instance, &create_info, 0, &vk.surface);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Vk_Context vk;
|
||||
|
||||
bool Vk_Setup(SDL_Window *window) {
|
||||
bool result = false;
|
||||
|
||||
vk.lib = Vk_LoadLibrary();
|
||||
|
||||
// Create instance
|
||||
//
|
||||
if (vk.err == VK_SUCCESS) {
|
||||
vk.CreateInstance = (PFN_vkCreateInstance) vk.GetInstanceProcAddr(0, "vkCreateInstance");
|
||||
|
||||
const char *extensions[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_PLATFORM_SURFACE_EXTENSION,
|
||||
|
||||
#if !LD_RELEASE
|
||||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME
|
||||
#endif
|
||||
};
|
||||
|
||||
const char *layers[] = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
|
||||
U32 n_layers = LD_RELEASE ? 0 : ArraySize(layers);
|
||||
|
||||
VkApplicationInfo app = { 0 };
|
||||
app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
app.apiVersion = VK_API_VERSION_1_3; // I know 1.4 is out
|
||||
|
||||
VkInstanceCreateInfo create_info = { 0 };
|
||||
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
create_info.pApplicationInfo = &app;
|
||||
create_info.ppEnabledExtensionNames = extensions;
|
||||
create_info.enabledExtensionCount = ArraySize(extensions);
|
||||
create_info.ppEnabledLayerNames = layers;
|
||||
create_info.enabledLayerCount = n_layers;
|
||||
|
||||
vk.err = vk.CreateInstance(&create_info, 0, &vk.instance);
|
||||
}
|
||||
|
||||
// Load instance level functions and create window surface
|
||||
//
|
||||
if (vk.err == VK_SUCCESS) {
|
||||
#define VK_INSTANCE_FUNCTIONS
|
||||
#define VK_FUNC(x) vk.x = (PFN_vk##x) vk.GetInstanceProcAddr(vk.instance, Stringify(Glue(vk, x)))
|
||||
#include "functions.h"
|
||||
#undef VK_FUNC
|
||||
|
||||
Vk_CreateSurface(window);
|
||||
}
|
||||
|
||||
// Select GPU
|
||||
//
|
||||
if (vk.err == VK_SUCCESS) {
|
||||
VkPhysicalDevice devices[8] = { 0 };
|
||||
U32 n_devices;
|
||||
|
||||
vk.EnumeratePhysicalDevices(vk.instance, &n_devices, 0);
|
||||
vk.EnumeratePhysicalDevices(vk.instance, &n_devices, devices);
|
||||
|
||||
vk.gpu = devices[0];
|
||||
|
||||
for (U32 it = 0; it < n_devices; ++it) {
|
||||
VkPhysicalDeviceProperties props;
|
||||
vk.GetPhysicalDeviceProperties(devices[it], &props);
|
||||
|
||||
if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||
vk.gpu = devices[it];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vk.gpu != VK_NULL_HANDLE) {
|
||||
VkQueueFamilyProperties qprops[32] = { 0 };
|
||||
U32 n_qprops = 0;
|
||||
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties(vk.gpu, &n_qprops, 0);
|
||||
vk.GetPhysicalDeviceQueueFamilyProperties(vk.gpu, &n_qprops, qprops);
|
||||
|
||||
for (U32 it = 0; it < n_qprops; ++it) {
|
||||
if (qprops[it].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
// Assumed combined graphics-present queue, this is the case on all desktop class
|
||||
// gpus
|
||||
vk.queue.family = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("[Error] :: Failed to create instance\n");
|
||||
}
|
||||
|
||||
// Create logical device
|
||||
//
|
||||
if (vk.gpu != VK_NULL_HANDLE) {
|
||||
const char *extensions[] = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
|
||||
VkPhysicalDeviceVulkan11Features features11 = { 0 };
|
||||
features11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
|
||||
features11.storageBuffer16BitAccess = VK_TRUE;
|
||||
features11.uniformAndStorageBuffer16BitAccess = VK_TRUE;
|
||||
|
||||
VkPhysicalDeviceVulkan12Features features12 = { 0 };
|
||||
features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
||||
features12.pNext = &features11;
|
||||
features12.shaderFloat16 = VK_TRUE;
|
||||
features12.shaderInt8 = VK_TRUE;
|
||||
features12.storageBuffer8BitAccess = VK_TRUE;
|
||||
features12.uniformAndStorageBuffer8BitAccess = VK_TRUE;
|
||||
features12.descriptorIndexing = VK_TRUE;
|
||||
|
||||
// @Todo: we will probably need to enable some of the 'nonuniform' indexing features
|
||||
|
||||
VkPhysicalDeviceVulkan13Features features13 = { 0 };
|
||||
features13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
|
||||
features13.pNext = &features12;
|
||||
features13.synchronization2 = VK_TRUE;
|
||||
features13.dynamicRendering = VK_TRUE;
|
||||
|
||||
F32 priority = 1.0f;
|
||||
|
||||
VkDeviceQueueCreateInfo queue_info = { 0 };
|
||||
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_info.queueFamilyIndex = vk.queue.family;
|
||||
queue_info.queueCount = 1;
|
||||
queue_info.pQueuePriorities = &priority;
|
||||
|
||||
VkDeviceCreateInfo create_info = { 0 };
|
||||
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
create_info.pNext = &features13;
|
||||
create_info.queueCreateInfoCount = 1;
|
||||
create_info.pQueueCreateInfos = &queue_info;
|
||||
create_info.enabledExtensionCount = ArraySize(extensions);
|
||||
create_info.ppEnabledExtensionNames = extensions;
|
||||
create_info.pEnabledFeatures = 0;
|
||||
|
||||
vk.err = vk.CreateDevice(vk.gpu, &create_info, 0, &vk.device);
|
||||
}
|
||||
else {
|
||||
printf("[Error] :: Failed to find suitable GPU\n");
|
||||
vk.err = VK_ERROR_DEVICE_LOST;
|
||||
}
|
||||
|
||||
if (vk.err == VK_SUCCESS) {
|
||||
// Load device level functions and acquire the device queue
|
||||
#define VK_DEVICE_FUNCTIONS
|
||||
#define VK_FUNC(x) vk.x = (PFN_vk##x) vk.GetDeviceProcAddr(vk.device, Stringify(Glue(vk, x)))
|
||||
#include "functions.h"
|
||||
#undef VK_FUNC
|
||||
|
||||
vk.GetDeviceQueue(vk.device, vk.queue.family, 0, &vk.queue.handle);
|
||||
|
||||
// Create swapchain
|
||||
U32 n_images = 2;
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR caps;
|
||||
vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(vk.gpu, vk.surface, &caps);
|
||||
|
||||
if (caps.currentExtent.width == -1) {
|
||||
int w, h;
|
||||
SDL_GetWindowSizeInPixels(window, &w, &h);
|
||||
|
||||
vk.swapchain.width = w;
|
||||
vk.swapchain.height = h;
|
||||
}
|
||||
else {
|
||||
vk.swapchain.width = caps.currentExtent.width;
|
||||
vk.swapchain.height = caps.currentExtent.height;
|
||||
}
|
||||
|
||||
n_images = Max(n_images, caps.minImageCount);
|
||||
}
|
||||
|
||||
{
|
||||
VkSurfaceFormatKHR formats[32];
|
||||
U32 n_formats = 0;
|
||||
|
||||
vk.GetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &n_formats, 0);
|
||||
vk.GetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &n_formats, formats);
|
||||
|
||||
vk.swapchain.format = formats[0];
|
||||
|
||||
for (U32 it = 0; it < n_formats; ++it) {
|
||||
VkSurfaceFormatKHR *fmt = &formats[it];
|
||||
|
||||
if ((fmt->format == VK_FORMAT_B8G8R8A8_SRGB) ||
|
||||
(fmt->format == VK_FORMAT_R8G8B8A8_SRGB))
|
||||
{
|
||||
if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||
vk.swapchain.format = formats[it];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR create_info = { 0 };
|
||||
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
create_info.surface = vk.surface;
|
||||
create_info.minImageCount = n_images;
|
||||
create_info.imageFormat = vk.swapchain.format.format;
|
||||
create_info.imageColorSpace = vk.swapchain.format.colorSpace;
|
||||
create_info.imageExtent = (VkExtent2D) { vk.swapchain.width, vk.swapchain.height };
|
||||
create_info.imageArrayLayers = 1;
|
||||
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
create_info.clipped = VK_TRUE;
|
||||
|
||||
vk.err = vk.CreateSwapchainKHR(vk.device, &create_info, 0, &vk.swapchain.handle);
|
||||
|
||||
vk.swapchain.n_images = n_images;
|
||||
}
|
||||
else {
|
||||
printf("[Error] :: Failed to create device\n");
|
||||
}
|
||||
|
||||
if (vk.err == VK_SUCCESS) {
|
||||
// Get the swapchain images and create image views using them
|
||||
U32 n_images = 0;
|
||||
vk.GetSwapchainImagesKHR(vk.device, vk.swapchain.handle, &n_images, 0);
|
||||
vk.GetSwapchainImagesKHR(vk.device, vk.swapchain.handle, &n_images, vk.swapchain.images);
|
||||
|
||||
if (n_images != vk.swapchain.n_images) {
|
||||
printf("[Warn] :: Swapchain image count mismatch\n");
|
||||
vk.swapchain.n_images = n_images;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo create_info = { 0 };
|
||||
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
create_info.format = vk.swapchain.format.format;
|
||||
|
||||
create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
create_info.subresourceRange.levelCount = 1;
|
||||
create_info.subresourceRange.layerCount = 1;
|
||||
|
||||
for (U32 it = 0; it < n_images && vk.err == VK_SUCCESS; ++it) {
|
||||
create_info.image = vk.swapchain.images[it];
|
||||
vk.err = vk.CreateImageView(vk.device, &create_info, 0, &vk.swapchain.views[it]);
|
||||
}
|
||||
}
|
||||
|
||||
for (U32 it = 0; it < VK_FRAMES_IN_FLIGHT && vk.err == VK_SUCCESS; ++it) {
|
||||
Vk_Frame *frame = &vk.frames[it];
|
||||
|
||||
VkCommandPoolCreateInfo pool = { 0 };
|
||||
pool.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
pool.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
||||
pool.queueFamilyIndex = vk.queue.family;
|
||||
|
||||
VkResult err = vk.CreateCommandPool(vk.device, &pool, 0, &frame->pool);
|
||||
|
||||
VkCommandBufferAllocateInfo alloc = { 0 };
|
||||
alloc.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
alloc.commandBufferCount = 1;
|
||||
alloc.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
alloc.commandPool = frame->pool;
|
||||
|
||||
vk.AllocateCommandBuffers(vk.device, &alloc, &frame->cmd);
|
||||
|
||||
VkSemaphoreCreateInfo semaphore = { 0 };
|
||||
semaphore.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
err = Min(vk.CreateSemaphore(vk.device, &semaphore, 0, &frame->acquire), err);
|
||||
err = Min(vk.CreateSemaphore(vk.device, &semaphore, 0, &frame->complete), err);
|
||||
|
||||
VkFenceCreateInfo fence = { 0 };
|
||||
fence.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
err = Min(vk.CreateFence(vk.device, &fence, 0, &frame->fence), err);
|
||||
|
||||
vk.err = err;
|
||||
}
|
||||
|
||||
result = (vk.err == VK_SUCCESS);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vk_Frame *Vk_FrameBegin(SDL_Window *window) {
|
||||
(void) window; // might need this for the resize later
|
||||
Vk_Frame *frame = &vk.frames[vk.n_frames & 1];
|
||||
|
||||
vk.WaitForFences(vk.device, 1, &frame->fence, VK_TRUE, UINT64_MAX);
|
||||
|
||||
vk.ResetFences(vk.device, 1, &frame->fence);
|
||||
vk.ResetCommandPool(vk.device, frame->pool, 0);
|
||||
|
||||
VkResult res = vk.AcquireNextImageKHR(vk.device, vk.swapchain.handle, UINT64_MAX, frame->acquire, 0, &frame->image);
|
||||
(void) res; // @Todo: check res to see if swapchain is out of date and rebuild
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = { 0 };
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
|
||||
vk.BeginCommandBuffer(frame->cmd, &begin_info);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void Vk_FrameEnd() {
|
||||
Vk_Frame *frame = &vk.frames[vk.n_frames & 1];
|
||||
|
||||
vk.EndCommandBuffer(frame->cmd);
|
||||
|
||||
VkPipelineStageFlags stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
||||
VkSubmitInfo submit = { 0 };
|
||||
submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit.waitSemaphoreCount = 1;
|
||||
submit.pWaitSemaphores = &frame->acquire;
|
||||
submit.pWaitDstStageMask = &stage;
|
||||
submit.commandBufferCount = 1;
|
||||
submit.pCommandBuffers = &frame->cmd;
|
||||
submit.signalSemaphoreCount = 1;
|
||||
submit.pSignalSemaphores = &frame->complete;
|
||||
|
||||
vk.QueueSubmit(vk.queue.handle, 1, &submit, frame->fence);
|
||||
|
||||
VkPresentInfoKHR present = { 0 };
|
||||
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
present.waitSemaphoreCount = 1;
|
||||
present.pWaitSemaphores = &frame->complete;
|
||||
present.swapchainCount = 1;
|
||||
present.pSwapchains = &vk.swapchain.handle;
|
||||
present.pImageIndices = &frame->image;
|
||||
|
||||
vk.QueuePresentKHR(vk.queue.handle, &present);
|
||||
|
||||
vk.n_frames += 1;
|
||||
}
|
||||
80
code/vulkan/core.h
Normal file
80
code/vulkan/core.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#if !defined(LD_VULKAN_CORE_H_)
|
||||
#define LD_VULKAN_CORE_H_
|
||||
|
||||
#if OS_WINDOWS
|
||||
#define VK_USE_PLATFORM_WIN32_KHR 1
|
||||
|
||||
#if defined(CreateSemaphore)
|
||||
// Sigh
|
||||
#undef CreateSemaphore
|
||||
#endif
|
||||
#elif OS_LINUX
|
||||
#define VK_USE_PLATFORM_XLIB_KHR 1
|
||||
#define VK_USE_PLATFORM_WAYLAND_KHR 1
|
||||
#endif
|
||||
|
||||
#define VK_NO_PROTOTYPES 1
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define VK_FRAMES_IN_FLIGHT 2
|
||||
|
||||
typedef struct Vk_Frame Vk_Frame;
|
||||
struct Vk_Frame {
|
||||
VkCommandPool pool;
|
||||
VkCommandBuffer cmd;
|
||||
|
||||
VkSemaphore acquire, complete;
|
||||
VkFence fence;
|
||||
|
||||
U32 image; // swapchain image index
|
||||
};
|
||||
|
||||
typedef struct Vk_Context Vk_Context;
|
||||
struct Vk_Context {
|
||||
void *lib;
|
||||
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
||||
PFN_vkCreateInstance CreateInstance;
|
||||
|
||||
#define VK_INSTANCE_FUNCTIONS
|
||||
#define VK_DEVICE_FUNCTIONS
|
||||
#define VK_FUNC(x) PFN_vk##x x
|
||||
#include "functions.h"
|
||||
#undef VK_FUNC
|
||||
|
||||
VkResult err;
|
||||
VkInstance instance;
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
VkPhysicalDevice gpu;
|
||||
VkDevice device;
|
||||
|
||||
U32 n_frames; // monotonically increasing
|
||||
Vk_Frame frames[VK_FRAMES_IN_FLIGHT];
|
||||
|
||||
struct {
|
||||
U32 family;
|
||||
VkQueue handle;
|
||||
} queue;
|
||||
|
||||
struct {
|
||||
VkSwapchainKHR handle;
|
||||
|
||||
U32 n_images;
|
||||
VkImage images[8];
|
||||
VkImageView views[8];
|
||||
|
||||
VkSurfaceFormatKHR format;
|
||||
|
||||
U32 width;
|
||||
U32 height;
|
||||
} swapchain;
|
||||
};
|
||||
|
||||
extern Vk_Context vk;
|
||||
|
||||
static bool Vk_Setup(SDL_Window *window);
|
||||
static Vk_Frame *Vk_FrameBegin(SDL_Window *window);
|
||||
static void Vk_FrameEnd();
|
||||
|
||||
#endif // LD_VULKAN_CORE_H_
|
||||
38
code/vulkan/functions.h
Normal file
38
code/vulkan/functions.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#if defined(VK_INSTANCE_FUNCTIONS)
|
||||
VK_FUNC(EnumeratePhysicalDevices);
|
||||
VK_FUNC(GetPhysicalDeviceQueueFamilyProperties);
|
||||
VK_FUNC(GetPhysicalDeviceProperties);
|
||||
VK_FUNC(CreateDevice);
|
||||
VK_FUNC(GetDeviceProcAddr);
|
||||
VK_FUNC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
VK_FUNC(GetPhysicalDeviceSurfaceFormatsKHR);
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
VK_FUNC(CreateWin32SurfaceKHR);
|
||||
#endif
|
||||
#undef VK_INSTANCE_FUNCTIONS
|
||||
#endif
|
||||
|
||||
#if defined(VK_DEVICE_FUNCTIONS)
|
||||
VK_FUNC(GetDeviceQueue);
|
||||
VK_FUNC(CreateSwapchainKHR);
|
||||
VK_FUNC(GetSwapchainImagesKHR);
|
||||
VK_FUNC(CreateImageView);
|
||||
VK_FUNC(CreateCommandPool);
|
||||
VK_FUNC(CreateSemaphore);
|
||||
VK_FUNC(CreateFence);
|
||||
VK_FUNC(AllocateCommandBuffers);
|
||||
VK_FUNC(WaitForFences);
|
||||
VK_FUNC(ResetFences);
|
||||
VK_FUNC(ResetCommandPool);
|
||||
VK_FUNC(AcquireNextImageKHR);
|
||||
VK_FUNC(QueueSubmit);
|
||||
VK_FUNC(QueuePresentKHR);
|
||||
VK_FUNC(BeginCommandBuffer);
|
||||
VK_FUNC(EndCommandBuffer);
|
||||
|
||||
VK_FUNC(CmdPipelineBarrier2);
|
||||
VK_FUNC(CmdBeginRendering);
|
||||
VK_FUNC(CmdEndRendering);
|
||||
#undef VK_DEVICE_FUNCTIONS
|
||||
#endif
|
||||
11
windows.bat
11
windows.bat
@@ -14,6 +14,11 @@ FOR %%A in (%*) DO (
|
||||
SET %%A=1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%VULKAN_SDK%" (
|
||||
ECHO [Error: Vulkan SDK required to build]
|
||||
EXIT /b 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "deps\SDL3" (
|
||||
SET deps=1
|
||||
)
|
||||
@@ -48,15 +53,15 @@ IF %deps% equ 1 (
|
||||
|
||||
ECHO [Building source]
|
||||
|
||||
SET COMPILER_OPTS=-nologo -W4 -I"deps\SDL3\include" -I"deps\stb"
|
||||
SET COMPILER_OPTS=-nologo -W4 -I"deps\SDL3\include" -I"deps\stb" -I"%VULKAN_SDK%\Include"
|
||||
SET LINKER_OPTS=-LIBPATH:"deps\SDL3\lib" SDL3.lib
|
||||
|
||||
IF %release% equ 1 (
|
||||
ECHO [Release build]
|
||||
cl -O2 -WX %COMPILER_OPTS% "..\code\first.c" -link %LINKER_OPTS%
|
||||
cl -O2 -WX %COMPILER_OPTS% -DLD_RELEASE=1 "%~dp0code\first.c" -link %LINKER_OPTS%
|
||||
) ELSE (
|
||||
ECHO [Debug build]
|
||||
cl -Od -Zi %COMPILER_OPTS% "..\code\first.c" -link %LINKER_OPTS%
|
||||
cl -Od -Zi %COMPILER_OPTS% "%~dp0code\first.c" -link %LINKER_OPTS%
|
||||
)
|
||||
|
||||
POPD
|
||||
|
||||
Reference in New Issue
Block a user