various updates
This commit is contained in:
parent
6937e55888
commit
97adb0dffa
@ -49,16 +49,20 @@ runtime_lib = library('vyrt',
|
||||
'src/runtime/threading.h',
|
||||
'src/runtime/app.h',
|
||||
'src/runtime/dynamic_libs.h',
|
||||
'src/runtime/jobs.h',
|
||||
|
||||
'src/runtime/error_report.c',
|
||||
'src/runtime/gfx_main.c',
|
||||
'src/runtime/gfx_shader_loading.c',
|
||||
'src/runtime/config.c',
|
||||
'src/runtime/runtime_cvars.c',
|
||||
'src/runtime/threading.c',
|
||||
'src/runtime/threading_mutex.c',
|
||||
'src/runtime/threading_thread.c',
|
||||
'src/runtime/threading_cond.c',
|
||||
'src/runtime/fio.c',
|
||||
'src/runtime/app.c',
|
||||
'src/runtime/dynamic_libs.c',
|
||||
'src/runtime/jobs.c',
|
||||
|
||||
# Contrib Sources
|
||||
'contrib/xxhash/xxhash.c',
|
||||
@ -87,7 +91,7 @@ if vk_dep.found()
|
||||
# Contrib Sources
|
||||
'contrib/volk/volk.h',
|
||||
'contrib/volk/volk.c',
|
||||
dependencies : [m_dep, vk_inc_dep],
|
||||
dependencies : [m_dep, vk_inc_dep, windowing_dep],
|
||||
include_directories : incdir,
|
||||
link_with : [runtime_lib],
|
||||
c_pch : 'pch/vk_pch.h',
|
||||
|
@ -8,13 +8,14 @@
|
||||
int WINAPI wWinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
PWSTR pCmdLine,
|
||||
int nCmdShow) { return vyWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
|
||||
int nCmdShow) {
|
||||
return vyWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return 0;
|
||||
return vyXlibEntry(argc, argv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
22
src/renderer/vk/framebuffer.h
Normal file
22
src/renderer/vk/framebuffer.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef VY_VK_FRAMEBUFFER_H
|
||||
#define VY_VK_FRAMEBUFFER_H
|
||||
|
||||
#include <volk/volk.h>
|
||||
|
||||
typedef struct {
|
||||
VkFramebuffer framebuffer;
|
||||
uint32_t pass_idx;
|
||||
} vy_framebuffer;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
} vy_framebuffer_handle;
|
||||
|
||||
/* Reserve a slot, but don't actually create the framebuffer yet.
|
||||
* We can use this if we are unsure if the framebuffer will really be needed.
|
||||
*/
|
||||
vy_framebuffer_handle vy_reserve_framebuffer(void);
|
||||
|
||||
vy_framebuffer *vy_get_framebuffer(vy_framebuffer_handle handle);
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#include "runtime/runtime.h"
|
||||
#include "runtime/gfx.h"
|
||||
#include "runtime/runtime.h"
|
||||
|
||||
#include "runtime/renderer_api.h"
|
||||
|
||||
@ -17,7 +17,7 @@ typedef struct {
|
||||
|
||||
static vy_pipeline_storage _storage;
|
||||
|
||||
static vy_gfx_pipeline_id StorePipeline(vy_gl_pipeline pipeline) {
|
||||
static vy_gfx_pipeline_handle StorePipeline(vy_gl_pipeline pipeline) {
|
||||
/* Search for free slot */
|
||||
uint32_t slot = NUM_SLOTS;
|
||||
for (uint32_t i = 0; i < NUM_SLOTS; ++i) {
|
||||
@ -28,7 +28,7 @@ static vy_gfx_pipeline_id StorePipeline(vy_gl_pipeline pipeline) {
|
||||
}
|
||||
if (slot == NUM_SLOTS) {
|
||||
vyReportError("GL_GFX", "Ran out of pipeline storage slots");
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
|
||||
uint32_t generation = _storage.generation_in_use[slot] >> 1;
|
||||
@ -37,12 +37,12 @@ static vy_gfx_pipeline_id StorePipeline(vy_gl_pipeline pipeline) {
|
||||
_storage.pipelines[slot] = pipeline;
|
||||
_storage.generation_in_use[slot] = (generation << 1) | 0x1;
|
||||
|
||||
vy_gfx_pipeline_id id;
|
||||
vy_gfx_pipeline_handle id;
|
||||
id.index = (generation << 27) | slot;
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ReleasePipelineSlot(vy_gfx_pipeline_id id) {
|
||||
static void ReleasePipelineSlot(vy_gfx_pipeline_handle id) {
|
||||
uint32_t slot = id.index & 0x08ffffff;
|
||||
uint32_t gen = (id.index >> 27) & 0x1f;
|
||||
if (slot >= NUM_SLOTS)
|
||||
@ -52,7 +52,7 @@ static void ReleasePipelineSlot(vy_gfx_pipeline_id id) {
|
||||
_storage.generation_in_use[slot] &= ~0x1;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT vy_gfx_pipeline_id
|
||||
VY_DLLEXPORT vy_gfx_pipeline_handle
|
||||
vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
|
||||
#if 0
|
||||
char info_log[512];
|
||||
@ -74,7 +74,7 @@ vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
|
||||
info_log);
|
||||
glDeleteProgram(prog);
|
||||
glDeleteShader(shader);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
glAttachShader(prog, shader);
|
||||
glLinkProgram(prog);
|
||||
@ -84,20 +84,20 @@ vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
|
||||
vyReportError("GL_GFX", "Failed to link compute shader\n%s", info_log);
|
||||
glDeleteShader(shader);
|
||||
glDeleteProgram(prog);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
glDeleteShader(shader);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vy_gl_pipeline pipeline;
|
||||
pipeline.prog = 0;
|
||||
return StorePipeline(pipeline);
|
||||
}
|
||||
|
||||
VY_DLLEXPORT vy_gfx_pipeline_id
|
||||
VY_DLLEXPORT vy_gfx_pipeline_handle
|
||||
vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
|
||||
|
||||
#if 0
|
||||
#if 0
|
||||
char info_log[512];
|
||||
GLuint prog = glCreateProgram();
|
||||
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||
@ -118,7 +118,7 @@ vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
glDeleteProgram(prog);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
glAttachShader(prog, vertex_shader);
|
||||
|
||||
@ -134,7 +134,7 @@ vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
|
||||
glDeleteShader(fragment_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
glDeleteProgram(prog);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
glAttachShader(prog, fragment_shader);
|
||||
|
||||
@ -146,12 +146,12 @@ vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
glDeleteProgram(prog);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vy_gl_pipeline pipeline;
|
||||
pipeline.prog = 0;
|
||||
|
@ -92,11 +92,11 @@ VY_DLLEXPORT void vyRegisterCVars(void) {
|
||||
vyRegisterCVAR(&r_VkPreferMailboxMode);
|
||||
}
|
||||
|
||||
static int CreateInstance(void) {
|
||||
static vy_result CreateInstance(void) {
|
||||
VkResult result = volkInitialize();
|
||||
if (result != VK_SUCCESS) {
|
||||
vyReportError("vk", "Initialization failed: volkInitialize()");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
VkApplicationInfo app_info = {
|
||||
@ -160,7 +160,7 @@ static int CreateInstance(void) {
|
||||
result = vkCreateInstance(&instance_info, g_gpu.alloc_cb, &g_gpu.instance);
|
||||
if (result != VK_SUCCESS) {
|
||||
vyReportError("vk", "Failed to create the vulkan instance.");
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
volkLoadInstance(g_gpu.instance);
|
||||
|
||||
@ -179,10 +179,10 @@ static int CreateInstance(void) {
|
||||
g_gpu.alloc_cb,
|
||||
&g_gpu.messenger);
|
||||
#endif
|
||||
return 0;
|
||||
return VY_SUCCESS;
|
||||
}
|
||||
|
||||
static int CreateSurface(const vy_renderer_init_info *info) {
|
||||
static vy_result CreateSurface(const vy_renderer_init_info *info) {
|
||||
#ifdef _WIN32
|
||||
g_gpu.native_window.hInstance = info->hInstance;
|
||||
g_gpu.native_window.hWnd = info->hWnd;
|
||||
@ -195,24 +195,24 @@ static int CreateSurface(const vy_renderer_init_info *info) {
|
||||
&surface_info,
|
||||
g_gpu.alloc_cb,
|
||||
&g_gpu.surface) == VK_SUCCESS)
|
||||
return 0;
|
||||
return VY_SUCCESS;
|
||||
else
|
||||
return -100;
|
||||
return 100;
|
||||
#elif defined(VY_USE_XLIB_KHR)
|
||||
g_gpu.native_window.display = info->display;
|
||||
g_gpu.native_window.window = info->window;
|
||||
VkXlibSurfaceCreateInfoKHR surface_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||
.dpy = info->display,
|
||||
.window = info->window,
|
||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||
.dpy = info->display,
|
||||
.window = info->window,
|
||||
};
|
||||
if (vkCreateXlibSurfaceKHR(g_gpu.instance,
|
||||
&surface_info,
|
||||
&g_gpu.alloc_cb,
|
||||
&g_gpu.surface) == VK_SUCCESS)
|
||||
return 0;
|
||||
return VY_SUCCESS;
|
||||
else
|
||||
return -100;
|
||||
return 100;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -222,7 +222,8 @@ typedef struct {
|
||||
uint32_t present;
|
||||
} vy_queue_indices;
|
||||
|
||||
static vy_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev, VkSurfaceKHR surface) {
|
||||
static vy_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev,
|
||||
VkSurfaceKHR surface) {
|
||||
vy_queue_indices indices = {.graphics = UINT32_MAX,
|
||||
.compute = UINT32_MAX,
|
||||
.present = UINT32_MAX};
|
||||
@ -297,8 +298,7 @@ out:
|
||||
return supported;
|
||||
}
|
||||
|
||||
static int ChoosePhysicalDevice(void) {
|
||||
|
||||
static vy_result ChoosePhysicalDevice(void) {
|
||||
|
||||
g_gpu.phys_device = VK_NULL_HANDLE;
|
||||
uint32_t phys_device_count = 0;
|
||||
@ -306,7 +306,7 @@ static int ChoosePhysicalDevice(void) {
|
||||
vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, NULL);
|
||||
if (result != VK_SUCCESS) {
|
||||
vyReportError("vk", "Failed to enumerate the physical devices.");
|
||||
return -2;
|
||||
return 2;
|
||||
}
|
||||
VkPhysicalDevice *phys_devices =
|
||||
calloc(phys_device_count, sizeof(VkPhysicalDevice));
|
||||
@ -314,14 +314,13 @@ static int ChoosePhysicalDevice(void) {
|
||||
vyReportError(
|
||||
"vk",
|
||||
"Failed to enumerate the physical devices: Out of memory.");
|
||||
return -2;
|
||||
return 2;
|
||||
}
|
||||
vkEnumeratePhysicalDevices(g_gpu.instance,
|
||||
&phys_device_count,
|
||||
phys_devices);
|
||||
|
||||
|
||||
uint32_t highscore = 0;
|
||||
uint32_t highscore = 0;
|
||||
uint32_t best_index = phys_device_count;
|
||||
for (uint32_t i = 0; i < phys_device_count; ++i) {
|
||||
VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props = {
|
||||
@ -362,7 +361,7 @@ static int ChoosePhysicalDevice(void) {
|
||||
: 0;
|
||||
|
||||
if (score > highscore) {
|
||||
highscore = score;
|
||||
highscore = score;
|
||||
best_index = i;
|
||||
}
|
||||
|
||||
@ -392,12 +391,12 @@ static int ChoosePhysicalDevice(void) {
|
||||
|
||||
if (g_gpu.phys_device == VK_NULL_HANDLE) {
|
||||
vyReportError("vk", "Failed to find a suitable physical device.");
|
||||
return -3;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
return VY_SUCCESS;
|
||||
}
|
||||
|
||||
static int CreateDevice(void) {
|
||||
static vy_result CreateDevice(void) {
|
||||
const char *extensions[] = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
@ -432,15 +431,14 @@ static int CreateDevice(void) {
|
||||
queue_indices.present != queue_indices.compute) {
|
||||
queue_info[distinct_queue_count].sType =
|
||||
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_info[distinct_queue_count].pNext = NULL;
|
||||
queue_info[distinct_queue_count].flags = 0;
|
||||
queue_info[distinct_queue_count].pNext = NULL;
|
||||
queue_info[distinct_queue_count].flags = 0;
|
||||
queue_info[distinct_queue_count].queueCount = 1;
|
||||
queue_info[distinct_queue_count].queueFamilyIndex =
|
||||
queue_indices.present;
|
||||
queue_info[distinct_queue_count].pQueuePriorities = &priority;
|
||||
}
|
||||
|
||||
|
||||
VkDeviceCreateInfo device_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.enabledExtensionCount = VY_ARRAY_COUNT(extensions),
|
||||
@ -453,7 +451,7 @@ static int CreateDevice(void) {
|
||||
g_gpu.alloc_cb,
|
||||
&g_gpu.device) != VK_SUCCESS) {
|
||||
vyReportError("vk", "Device creation failed.");
|
||||
return -10;
|
||||
return 10;
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(g_gpu.device,
|
||||
@ -469,10 +467,10 @@ static int CreateDevice(void) {
|
||||
0,
|
||||
&g_gpu.present_queue);
|
||||
|
||||
return 0;
|
||||
return VY_SUCCESS;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) {
|
||||
VY_DLLEXPORT vy_result vyInit(const vy_renderer_init_info *info) {
|
||||
vyLog("vk", "Init");
|
||||
|
||||
_tracking_alloc_cbs.pUserData = NULL;
|
||||
@ -487,22 +485,22 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) {
|
||||
}
|
||||
|
||||
int res = CreateInstance();
|
||||
if (res != 0)
|
||||
if (res != VY_SUCCESS)
|
||||
return res;
|
||||
res = CreateSurface(info);
|
||||
if (res != 0)
|
||||
if (res != VY_SUCCESS)
|
||||
return res;
|
||||
res = ChoosePhysicalDevice();
|
||||
if (res != 0)
|
||||
if (res != VY_SUCCESS)
|
||||
return res;
|
||||
res = CreateDevice();
|
||||
if (res != 0)
|
||||
if (res != VY_SUCCESS)
|
||||
return res;
|
||||
res = vyCreateSwapchain();
|
||||
if (res != 0)
|
||||
if (res != VY_SUCCESS)
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
return VY_SUCCESS;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyShutdown(void) {
|
||||
|
@ -7,10 +7,10 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#elif defined(VY_USE_XLIB)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
VY_CVAR_I(r_VkPreferredSwapchainImages,
|
||||
@ -55,7 +55,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
|
||||
params.surface_format = formats[0];
|
||||
for (uint32_t i = 0; i < format_count; ++i) {
|
||||
if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
|
||||
formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||
formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||
params.surface_format = formats[i];
|
||||
break;
|
||||
}
|
||||
@ -72,14 +72,14 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
|
||||
#ifdef _WIN32
|
||||
RECT client_area;
|
||||
GetClientRect(g_gpu.native_window.hWnd, &client_area);
|
||||
params.extent.width = (uint32_t)client_area.right;
|
||||
params.extent.width = (uint32_t)client_area.right;
|
||||
params.extent.height = (uint32_t)client_area.bottom;
|
||||
#else
|
||||
XWindowAttributes attribs;
|
||||
XGetWindowAttributes(g_gpu.native_window.display,
|
||||
g_gpu.native_window.window,
|
||||
&attribs);
|
||||
params.extent.width = (uint32_t)attribs.width;
|
||||
params.extent.width = (uint32_t)attribs.width;
|
||||
params.extent.height = (uint32_t)attribs.height;
|
||||
#endif
|
||||
}
|
||||
@ -90,7 +90,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
|
||||
|
||||
vy_swapchain g_swapchain;
|
||||
|
||||
int vyCreateSwapchain(void) {
|
||||
vy_result vyCreateSwapchain(void) {
|
||||
vy_device_swapchain_parameters device_params =
|
||||
DetermineSwapchainParameters();
|
||||
|
||||
@ -117,22 +117,21 @@ int vyCreateSwapchain(void) {
|
||||
};
|
||||
uint32_t queue_families[] = {g_gpu.graphics_family, g_gpu.present_family};
|
||||
if (g_gpu.present_family != g_gpu.graphics_family) {
|
||||
swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
swapchain_info.pQueueFamilyIndices = queue_families;
|
||||
swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
swapchain_info.pQueueFamilyIndices = queue_families;
|
||||
swapchain_info.queueFamilyIndexCount = 2;
|
||||
} else {
|
||||
swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapchain_info.pQueueFamilyIndices = NULL;
|
||||
swapchain_info.queueFamilyIndexCount = 0;
|
||||
}
|
||||
|
||||
|
||||
if (vkCreateSwapchainKHR(g_gpu.device,
|
||||
&swapchain_info,
|
||||
g_gpu.alloc_cb,
|
||||
&g_swapchain.swapchain) != VK_SUCCESS) {
|
||||
vyReportError("vk", "Failed to create the swapchain");
|
||||
return -50;
|
||||
return 50;
|
||||
}
|
||||
g_swapchain.format = device_params.surface_format.format;
|
||||
|
||||
@ -146,7 +145,7 @@ int vyCreateSwapchain(void) {
|
||||
vyReportError("vk",
|
||||
"Unsupported number of swapchain images: %u",
|
||||
g_swapchain.image_count);
|
||||
return -51;
|
||||
return 51;
|
||||
}
|
||||
vkGetSwapchainImagesKHR(g_gpu.device,
|
||||
g_swapchain.swapchain,
|
||||
@ -156,37 +155,44 @@ int vyCreateSwapchain(void) {
|
||||
/* Create image views */
|
||||
for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
|
||||
VkImageViewCreateInfo view_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = g_swapchain.images[i],
|
||||
.format = g_swapchain.format,
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = g_swapchain.images[i],
|
||||
.format = g_swapchain.format,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.components = {
|
||||
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
},
|
||||
.subresourceRange = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
},
|
||||
.components =
|
||||
{
|
||||
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
},
|
||||
};
|
||||
if (vkCreateImageView(g_gpu.device,
|
||||
&view_info,
|
||||
g_gpu.alloc_cb,
|
||||
&view_info,
|
||||
g_gpu.alloc_cb,
|
||||
&g_swapchain.image_views[i]) != VK_SUCCESS) {
|
||||
vyReportError("vk",
|
||||
"Failed to create an image view for the swapchain.");
|
||||
return -52;
|
||||
return 52;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return VY_SUCCESS;
|
||||
}
|
||||
|
||||
vy_result vyRecreateSwapchain(void) {
|
||||
/* TODO(Kevin): Old swapchain in swapchain create info */
|
||||
vyDestroySwapchain();
|
||||
return vyCreateSwapchain();
|
||||
}
|
||||
|
||||
void vyDestroySwapchain(void) {
|
||||
for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <volk/volk.h>
|
||||
|
||||
#include "runtime/runtime.h"
|
||||
|
||||
#define VY_VK_MAX_SWAPCHAIN_IMAGES 3
|
||||
|
||||
typedef struct {
|
||||
@ -17,7 +19,9 @@ typedef struct {
|
||||
extern vy_swapchain g_swapchain;
|
||||
#endif
|
||||
|
||||
int vyCreateSwapchain(void);
|
||||
vy_result vyCreateSwapchain(void);
|
||||
|
||||
vy_result vyRecreateSwapchain(void);
|
||||
|
||||
void vyDestroySwapchain(void);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "app.h"
|
||||
#include "config.h"
|
||||
#include "fio.h"
|
||||
#include "gfx.h"
|
||||
#include "config.h"
|
||||
#include "renderer_api.h"
|
||||
|
||||
extern void __RegisterRuntimeCVars(void);
|
||||
@ -11,8 +11,8 @@ VY_CVAR_I(rt_WindowWidth, "Window width. Default: 1024", 1024);
|
||||
VY_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
static LRESULT CALLBACK win32WndProc(HWND hWnd,
|
||||
UINT uMsg,
|
||||
@ -28,9 +28,9 @@ static LRESULT CALLBACK win32WndProc(HWND hWnd,
|
||||
}
|
||||
|
||||
VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
PWSTR pCmdLine,
|
||||
int nCmdShow) {
|
||||
HINSTANCE hPrevInstance,
|
||||
PWSTR pCmdLine,
|
||||
int nCmdShow) {
|
||||
|
||||
__RegisterRuntimeCVars();
|
||||
vyRegisterRendererCVars();
|
||||
@ -43,7 +43,6 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
WNDCLASSEXW wndclass = {
|
||||
.cbSize = sizeof(wndclass),
|
||||
.hInstance = hInstance,
|
||||
@ -59,9 +58,9 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
|
||||
HWND wnd = NULL;
|
||||
if (rt_Fullscreen.i) {
|
||||
/* Fullscreen window */
|
||||
int w = GetSystemMetrics(SM_CXSCREEN);
|
||||
int h = GetSystemMetrics(SM_CYSCREEN);
|
||||
wnd = CreateWindowExW(WS_EX_APPWINDOW,
|
||||
int w = GetSystemMetrics(SM_CXSCREEN);
|
||||
int h = GetSystemMetrics(SM_CYSCREEN);
|
||||
wnd = CreateWindowExW(WS_EX_APPWINDOW,
|
||||
L"vyWndClass",
|
||||
L"Voyage",
|
||||
WS_POPUP,
|
||||
@ -130,4 +129,129 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(VY_USE_XLIB)
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static void
|
||||
xlibSetFullscreen(Display *dpy, int screen, Window window, bool enable) {
|
||||
Atom wm_state = XInternAtom(dpy, "_NET_W_STATE", False);
|
||||
Atom wm_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
if (wm_state == None || wm_fullscreen == None) {
|
||||
vyLog("CORE", "Window manager does not support fullscreen mode.");
|
||||
return;
|
||||
}
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0
|
||||
#define _NET_WM_STATE_ADD 1
|
||||
#define EVENT_SOURCE_APPLICATION 1
|
||||
XEvent ev;
|
||||
ev.type = ClientMessage;
|
||||
ev.xclient.display = dpy;
|
||||
ev.xclient.window = window;
|
||||
ev.xclient.message_type = wm_state;
|
||||
ev.xclient.format = 32;
|
||||
ev.xclient.data.l[0] = (enable) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||
ev.xclient.data.l[1] = wm_fullscreen;
|
||||
ev.xclient.data.l[2] = 0;
|
||||
ev.xclient.data.l[3] = EVENT_SOURCE_APPLICATION;
|
||||
ev.xclient.data.l[4] = 0;
|
||||
|
||||
Window root_window = XRootWindow(dpy, screen);
|
||||
long ev_mask = SubstructureRedirectMask;
|
||||
|
||||
if (!XSendEvent(dpy, root_window, False, ev_mask, &ev)) {
|
||||
vyReportError("CORE", "Failed to send x11 fullscreen event.");
|
||||
}
|
||||
|
||||
#undef _NET_WM_STATE_ADD
|
||||
#undef _NET_WM_STATE_REMOVE
|
||||
#undef EVENT_SOURCE_APPLICATION
|
||||
}
|
||||
|
||||
VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
|
||||
__RegisterRuntimeCVars();
|
||||
vyRegisterRendererCVars();
|
||||
|
||||
vy_fio_config fio_config = {0};
|
||||
if (!vyInitFIO(&fio_config)) {
|
||||
vyReportError("FIO", "Init failed.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
if (!dpy) {
|
||||
vyReportError("CORE", "Failed to open default display");
|
||||
return 1;
|
||||
}
|
||||
int screen = DefaultScreen(dpy);
|
||||
Window window;
|
||||
int w = rt_WindowWidth.i;
|
||||
int h = rt_WindowHeight.i;
|
||||
window = XCreateSimpleWindow(dpy,
|
||||
RootWindow(dpy, screen),
|
||||
10,
|
||||
10,
|
||||
w,
|
||||
h,
|
||||
1,
|
||||
BlackPixel(dpy, screen),
|
||||
WhitePixel(dpy, screen));
|
||||
XSelectInput(dpy, window, KeyPressMask);
|
||||
XMapWindow(dpy, window);
|
||||
XStoreName(dpy, window, "Voyage");
|
||||
|
||||
Atom wm_close = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
||||
if (!wm_close) {
|
||||
vyReportError("CORE", "Failed to find WM_DELETE_WINDOW atom.");
|
||||
XDestroyWindow(dpy, window);
|
||||
XCloseDisplay(dpy);
|
||||
return 1;
|
||||
}
|
||||
XSetWMProtocols(dpy, window, &wm_close, 1);
|
||||
|
||||
if (rt_Fullscreen.i)
|
||||
xlibSetFullscreen(dpy, screen, window, true);
|
||||
|
||||
vy_renderer_init_info renderer_info = {.display = dpy, .window = window};
|
||||
if (!vyInitGFX(&renderer_info)) {
|
||||
vyReportError("GFX", "Init failed.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Main Loop */
|
||||
bool keep_running = true;
|
||||
while (keep_running) {
|
||||
while (XEventsQueued(dpy, QueuedAlready) > 0) {
|
||||
XEvent event;
|
||||
XNextEvent(dpy, &event);
|
||||
switch (event.type) {
|
||||
case KeyPress:
|
||||
break;
|
||||
case ButtonPressMask:
|
||||
/* Mouse down */
|
||||
break;
|
||||
case PointerMotionMask:
|
||||
/* Mouse movement */
|
||||
break;
|
||||
case ClientMessage:
|
||||
if (event.xclient.data.l[0] == (long)wm_close) {
|
||||
vyLog("CORE", "Received WM_DELETE_WINDOW");
|
||||
keep_running = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vyShutdownGFX();
|
||||
XDestroyWindow(dpy, window);
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
vyShutdownFIO();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -11,9 +11,13 @@
|
||||
struct HINSTANCE__;
|
||||
|
||||
VY_DLLEXPORT int vyWin32Entry(struct HINSTANCE__ *hInstance,
|
||||
struct HINSTANCE__ *hPrevInstance,
|
||||
wchar_t *pCmdLine,
|
||||
int nCmdShow);
|
||||
struct HINSTANCE__ *hPrevInstance,
|
||||
wchar_t *pCmdLine,
|
||||
int nCmdShow);
|
||||
|
||||
#elif defined(VY_USE_XLIB)
|
||||
|
||||
VY_DLLEXPORT int vyXlibEntry(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -4,9 +4,13 @@
|
||||
#include "runtime.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define VY_DLLNAME(s) (s".dll")
|
||||
#define VY_DLLNAME(s) \
|
||||
(".\\"s \
|
||||
".dll")
|
||||
#elif defined(__linux__)
|
||||
#define VY_DLLNAME(s) ("lib"s".so")
|
||||
#define VY_DLLNAME(s) \
|
||||
("./lib"s \
|
||||
".so")
|
||||
#endif
|
||||
|
||||
typedef void *vy_dynlib;
|
||||
|
@ -59,7 +59,7 @@ static vy_file_tab _file_tab;
|
||||
#ifdef __linux__
|
||||
static pthread_t _thread;
|
||||
#elif defined(_WIN32)
|
||||
static HANDLE _fio_thread = NULL;
|
||||
static HANDLE _fio_thread = NULL;
|
||||
static HANDLE _fio_term_event = NULL;
|
||||
#endif
|
||||
|
||||
@ -406,8 +406,8 @@ static void ProcessRead(vy_file_op *op) {
|
||||
return;
|
||||
}
|
||||
|
||||
op->buffer.data = NULL;
|
||||
op->buffer.size = 0;
|
||||
op->buffer.data = NULL;
|
||||
op->buffer.size = 0;
|
||||
op->buffer.flags = 0;
|
||||
|
||||
FILE *file = fopen(path, "rb");
|
||||
@ -424,8 +424,8 @@ static void ProcessRead(vy_file_op *op) {
|
||||
op->buffer.size = (size_t)fsz;
|
||||
if (fread(op->buffer.data, fsz, 1, file) != 1) {
|
||||
free(op->buffer.data);
|
||||
op->buffer.data = NULL;
|
||||
op->buffer.size = 0;
|
||||
op->buffer.data = NULL;
|
||||
op->buffer.size = 0;
|
||||
op->buffer.flags = VY_FILE_BUFFER_FLAG_READ_FAILED;
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,7 @@
|
||||
|
||||
#include "runtime.h"
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
VY_FILE_BUFFER_FLAG_FILE_NOT_FOUND = 0x1,
|
||||
VY_FILE_BUFFER_FLAG_READ_FAILED = 0x2,
|
||||
};
|
||||
@ -19,7 +18,7 @@ typedef struct {
|
||||
uint32_t flags;
|
||||
} vy_file_buffer;
|
||||
|
||||
inline bool vyWasFileBufferSuccessful(const vy_file_buffer *fb) {
|
||||
static inline bool vyWasFileBufferSuccessful(const vy_file_buffer *fb) {
|
||||
return fb->flags == 0;
|
||||
}
|
||||
|
||||
@ -54,7 +53,7 @@ VY_DLLEXPORT void vyAbortFIO(vy_fio_handle fio);
|
||||
VY_DLLEXPORT bool vyIsFIOFinished(vy_fio_handle fio);
|
||||
|
||||
VY_DLLEXPORT bool vyRetrieveReadBuffer(vy_fio_handle fio,
|
||||
vy_file_buffer *buffer);
|
||||
vy_file_buffer *buffer);
|
||||
|
||||
VY_DLLEXPORT void vyFreeFileBuffer(vy_file_buffer buffer);
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
* - object renderer (for static models)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "runtime.h"
|
||||
|
||||
@ -23,12 +23,11 @@ VY_DLLEXPORT bool vyInitGFX(vy_renderer_init_info *renderer_info);
|
||||
|
||||
VY_DLLEXPORT void vyShutdownGFX(void);
|
||||
|
||||
/* Generational indices for backend objects */
|
||||
/* Handles backend objects */
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
} vy_gfx_pipeline_id;
|
||||
|
||||
#define VY_IS_GFX_ID_VALID(id) ((id).index != 0)
|
||||
} vy_gfx_pipeline_handle;
|
||||
|
||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
|
||||
* For example, an attribute might be bound to "CELL_GRID", which would be
|
||||
@ -52,7 +51,7 @@ typedef struct {
|
||||
vy_attribute_binding *storage_bindings;
|
||||
vy_attribute_binding *texture_bindings;
|
||||
|
||||
vy_gfx_pipeline_id pipeline;
|
||||
vy_gfx_pipeline_handle pipeline;
|
||||
|
||||
unsigned int uniform_binding_count;
|
||||
unsigned int storage_binding_count;
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
#define VY_DONT_DEFINE_RENDERER_GLOBAL
|
||||
|
||||
#include "gfx.h"
|
||||
#include "renderer_api.h"
|
||||
#include "config.h"
|
||||
#include "dynamic_libs.h"
|
||||
#include "gfx.h"
|
||||
#include "renderer_api.h"
|
||||
|
||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
|
||||
* For example, an attribute might be bound to "CELL_GRID", which would be
|
||||
@ -21,17 +21,18 @@ VY_CVAR_S(rt_Renderer,
|
||||
"Select the render backend. Available options: [vk], Default: vk",
|
||||
"vk");
|
||||
|
||||
extern bool vyLoadShaders(const char **paths, vy_shader *shaders, unsigned int count);
|
||||
extern bool
|
||||
vyLoadShaders(const char **paths, vy_shader *shaders, unsigned int count);
|
||||
|
||||
static bool LoadRenderer(void)
|
||||
{
|
||||
static bool LoadRenderer(void) {
|
||||
#define RETRIEVE_SYMBOL(name, type) \
|
||||
g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vy" #name); \
|
||||
if (!g_renderer.name) { \
|
||||
if (!g_renderer.name) { \
|
||||
vyReportError( \
|
||||
"GFX", \
|
||||
"Unable to retrieve renderer function %s from backend %s", \
|
||||
#name, rt_Renderer.s); \
|
||||
#name, \
|
||||
rt_Renderer.s); \
|
||||
}
|
||||
|
||||
if (strcmp(rt_Renderer.s, "vk") == 0) {
|
||||
@ -50,14 +51,16 @@ static bool LoadRenderer(void)
|
||||
vy_compile_graphics_pipeline_fn);
|
||||
return true;
|
||||
} else {
|
||||
vyReportError("GFX", "Unsupported renderer backend: (%s) %s", rt_Renderer.name, rt_Renderer.s);
|
||||
vyReportError("GFX",
|
||||
"Unsupported renderer backend: (%s) %s",
|
||||
rt_Renderer.name,
|
||||
rt_Renderer.s);
|
||||
return false;
|
||||
}
|
||||
#undef RETRIEVE_SYMBOL
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyRegisterRendererCVars(void)
|
||||
{
|
||||
VY_DLLEXPORT void vyRegisterRendererCVars(void) {
|
||||
if (!_renderer_loaded) {
|
||||
if (!LoadRenderer())
|
||||
return;
|
||||
@ -73,7 +76,7 @@ VY_DLLEXPORT bool vyInitGFX(vy_renderer_init_info *renderer_info) {
|
||||
g_renderer.RegisterCVars();
|
||||
}
|
||||
|
||||
if (g_renderer.Init(renderer_info) != 0)
|
||||
if (g_renderer.Init(renderer_info) != VY_SUCCESS)
|
||||
return false;
|
||||
|
||||
/* Init shader programs */
|
||||
|
@ -6,10 +6,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "runtime.h"
|
||||
#include "fio.h"
|
||||
#include "gfx.h"
|
||||
#include "handles.h"
|
||||
#include "renderer_api.h"
|
||||
#include "runtime.h"
|
||||
|
||||
typedef enum {
|
||||
VY_STMT_FORM_VALUE,
|
||||
@ -289,9 +290,9 @@ static vy_fio_handle DispatchShaderRead(const char *shader,
|
||||
return DispatchFileRead(path->value);
|
||||
}
|
||||
|
||||
static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
const char *file_path,
|
||||
unsigned int root_list) {
|
||||
static vy_gfx_pipeline_handle CreatePipeline(vy_parse_state *state,
|
||||
const char *file_path,
|
||||
unsigned int root_list) {
|
||||
/* Process the data */
|
||||
vy_fio_handle vertex_read =
|
||||
DispatchShaderRead("vertex", state, root_list, file_path);
|
||||
@ -309,22 +310,24 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
vyAbortFIO(vertex_read);
|
||||
vyAbortFIO(fragment_read);
|
||||
vyAbortFIO(compute_read);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
while (!vyIsFIOFinished(compute_read)) {
|
||||
/* wait */
|
||||
}
|
||||
vy_file_buffer compute_code;
|
||||
if (!vyRetrieveReadBuffer(compute_read, &compute_code) || !vyWasFileBufferSuccessful(&compute_code)) {
|
||||
if (!vyRetrieveReadBuffer(compute_read, &compute_code) ||
|
||||
!vyWasFileBufferSuccessful(&compute_code)) {
|
||||
vyReportError("GFX",
|
||||
"Failed to load compute shader required by: %s",
|
||||
file_path);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
vy_compute_pipeline_info info;
|
||||
info.compute_source = compute_code.data;
|
||||
info.compute_source_length = compute_code.size;
|
||||
vy_gfx_pipeline_id pipeline = g_renderer.CompileComputePipeline(&info);
|
||||
info.compute_source = compute_code.data;
|
||||
info.compute_source_length = compute_code.size;
|
||||
vy_gfx_pipeline_handle pipeline =
|
||||
g_renderer.CompileComputePipeline(&info);
|
||||
vyFreeFileBuffer(compute_code);
|
||||
return pipeline;
|
||||
} else if (vertex_read || fragment_read) {
|
||||
@ -336,7 +339,7 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
vyAbortFIO(vertex_read);
|
||||
vyAbortFIO(fragment_read);
|
||||
vyAbortFIO(compute_read);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
if (!vertex_read || !fragment_read) {
|
||||
vyReportError("GFX",
|
||||
@ -346,7 +349,7 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
vyAbortFIO(vertex_read);
|
||||
vyAbortFIO(fragment_read);
|
||||
vyAbortFIO(compute_read);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
|
||||
vy_graphics_pipeline_info info;
|
||||
@ -356,13 +359,14 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
int remaining = 2;
|
||||
while (remaining > 0) {
|
||||
if (vyIsFIOFinished(vertex_read)) {
|
||||
if (!vyRetrieveReadBuffer(vertex_read, &vertex_code) || !vyWasFileBufferSuccessful(&vertex_code)) {
|
||||
if (!vyRetrieveReadBuffer(vertex_read, &vertex_code) ||
|
||||
!vyWasFileBufferSuccessful(&vertex_code)) {
|
||||
vyReportError(
|
||||
"GFX",
|
||||
"Failed to load vertex shader required by: %s",
|
||||
file_path);
|
||||
vyFreeFileBuffer(fragment_code);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
info.vertex_source = vertex_code.data;
|
||||
info.vertex_source_length = vertex_code.size;
|
||||
@ -371,13 +375,14 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
}
|
||||
|
||||
if (vyIsFIOFinished(fragment_read)) {
|
||||
if (!vyRetrieveReadBuffer(fragment_read, &fragment_code) || !vyWasFileBufferSuccessful(&fragment_code)) {
|
||||
if (!vyRetrieveReadBuffer(fragment_read, &fragment_code) ||
|
||||
!vyWasFileBufferSuccessful(&fragment_code)) {
|
||||
vyReportError(
|
||||
"GFX",
|
||||
"Failed to load fragment shader required by: %s",
|
||||
file_path);
|
||||
vyFreeFileBuffer(vertex_code);
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
info.fragment_source = fragment_code.data;
|
||||
info.fragment_source_length = fragment_code.size;
|
||||
@ -386,7 +391,8 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
}
|
||||
}
|
||||
|
||||
vy_gfx_pipeline_id pipeline = g_renderer.CompileGraphicsPipeline(&info);
|
||||
vy_gfx_pipeline_handle pipeline =
|
||||
g_renderer.CompileGraphicsPipeline(&info);
|
||||
vyFreeFileBuffer(vertex_code);
|
||||
vyFreeFileBuffer(fragment_code);
|
||||
return pipeline;
|
||||
@ -399,7 +405,7 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
|
||||
vyAbortFIO(fragment_read);
|
||||
vyAbortFIO(compute_read);
|
||||
}
|
||||
return (vy_gfx_pipeline_id){0};
|
||||
return (vy_gfx_pipeline_handle){0};
|
||||
}
|
||||
|
||||
static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
|
||||
@ -516,7 +522,7 @@ ParseShaderFile(vy_file_id fid, vy_file_buffer fbuf, vy_shader *shader) {
|
||||
DbgPrintShaderFile(&state, root_list, 0);
|
||||
|
||||
shader->pipeline = CreatePipeline(&state, file_path, root_list);
|
||||
if (!VY_IS_GFX_ID_VALID(shader->pipeline)) {
|
||||
if (!VY_IS_HANDLE_VALID(shader->pipeline)) {
|
||||
result = false;
|
||||
goto out;
|
||||
}
|
||||
|
8
src/runtime/handles.h
Normal file
8
src/runtime/handles.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef VY_HANDLES_H
|
||||
#define VY_HANDLES_H
|
||||
|
||||
/* All handle types should contain a uint32_t index */
|
||||
|
||||
#define VY_IS_HANDLE_VALID(handle) ((handle).index != 0)
|
||||
|
||||
#endif
|
65
src/runtime/jobs.c
Normal file
65
src/runtime/jobs.c
Normal file
@ -0,0 +1,65 @@
|
||||
#include "jobs.h"
|
||||
#include "threading.h"
|
||||
|
||||
#define MAX_WORKERS 32
|
||||
#define JOB_QUEUE_SIZE 2048
|
||||
|
||||
/* A "chunk" of iterations for a particular job */
|
||||
typedef struct {
|
||||
uint32_t base_iteration;
|
||||
uint32_t iteration_count;
|
||||
vy_job_fn *fn;
|
||||
void *param;
|
||||
} vy_job_chunk;
|
||||
|
||||
typedef struct {
|
||||
/* Queue */
|
||||
struct {
|
||||
vy_job_chunk *chunks;
|
||||
unsigned int head;
|
||||
unsigned int tail;
|
||||
vy_condition_var *lock;
|
||||
} job_queue;
|
||||
|
||||
/* Thread data */
|
||||
vy_thread *thread;
|
||||
} vy_worker_data;
|
||||
|
||||
static volatile bool _keep_running = true;
|
||||
static vy_worker_data _worker_data[MAX_WORKERS];
|
||||
|
||||
static void ExecOneJobIfAvailable(vy_worker_data *wd) {
|
||||
if (wd->job_queue.head == wd->job_queue.tail) {
|
||||
/* No job available.
|
||||
* TODO: Pick one job queue at random and check if we can steal?
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
vy_job_chunk chunk = wd->job_queue.chunks[wd->job_queue.head];
|
||||
wd->job_queue.head = (wd->job_queue.head + 1) % JOB_QUEUE_SIZE;
|
||||
for (uint32_t i = 0; i < chunk.iteration_count; ++i) {
|
||||
chunk.fn(chunk.param, chunk.base_iteration + i);
|
||||
}
|
||||
}
|
||||
|
||||
static void WorkerEntry(void *param) {
|
||||
vy_worker_data *wd = param;
|
||||
while (_keep_running) {
|
||||
vyLockConditionVar(wd->job_queue.lock);
|
||||
while (wd->job_queue.head == wd->job_queue.tail && _keep_running) {
|
||||
vyWaitOnConditionVar(wd->job_queue.lock);
|
||||
}
|
||||
ExecOneJobIfAvailable(wd);
|
||||
vyUnlockConditionVar(wd->job_queue.lock, false);
|
||||
}
|
||||
}
|
||||
|
||||
void vyInitJobSystem(unsigned int worker_count) {
|
||||
if (worker_count > MAX_WORKERS)
|
||||
worker_count = MAX_WORKERS;
|
||||
|
||||
for (unsigned int i = 0; i < worker_count; ++i) {
|
||||
_worker_data[i].thread = vySpawnThread(WorkerEntry, &_worker_data[i]);
|
||||
}
|
||||
}
|
20
src/runtime/jobs.h
Normal file
20
src/runtime/jobs.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef VY_JOBS_H
|
||||
#define VY_JOBS_H
|
||||
|
||||
/* Work stealing job scheduler */
|
||||
|
||||
#include "runtime.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void vy_job_fn(void *param, uint32_t iteration);
|
||||
|
||||
typedef struct {
|
||||
uint32_t iterations;
|
||||
vy_job_fn *fn;
|
||||
void *param;
|
||||
} vy_job_decl;
|
||||
|
||||
VY_DLLEXPORT void vyDispatchJob(const vy_job_decl *decl);
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "gfx.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
struct HINSTANCE__;
|
||||
@ -38,11 +39,11 @@ typedef struct {
|
||||
} vy_graphics_pipeline_info;
|
||||
|
||||
typedef void vy_register_renderer_cvars_fn(void);
|
||||
typedef int vy_init_renderer_fn(const vy_renderer_init_info *info);
|
||||
typedef vy_result vy_init_renderer_fn(const vy_renderer_init_info *info);
|
||||
typedef void vy_shutdown_renderer_fn(void);
|
||||
typedef vy_gfx_pipeline_id
|
||||
typedef vy_gfx_pipeline_handle
|
||||
vy_compile_compute_pipeline_fn(const vy_compute_pipeline_info *info);
|
||||
typedef vy_gfx_pipeline_id
|
||||
typedef vy_gfx_pipeline_handle
|
||||
vy_compile_graphics_pipeline_fn(const vy_graphics_pipeline_info *info);
|
||||
|
||||
typedef struct {
|
||||
|
@ -6,14 +6,17 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define VY_DLLEXPORT __declspec(dllexport)
|
||||
#define VY_DLLEXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define VY_DLLEXPORT
|
||||
#define VY_DLLEXPORT
|
||||
#endif
|
||||
|
||||
#define VY_UNUSED(x) ((void)sizeof((x)))
|
||||
#define VY_UNUSED(x) ((void)sizeof((x)))
|
||||
#define VY_ARRAY_COUNT(x) (sizeof((x)) / sizeof((x)[0]))
|
||||
|
||||
typedef unsigned int vy_result;
|
||||
#define VY_SUCCESS 0
|
||||
|
||||
typedef struct {
|
||||
const char *start;
|
||||
unsigned int length;
|
||||
|
@ -17,4 +17,25 @@ VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex);
|
||||
|
||||
VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex);
|
||||
|
||||
typedef struct vy_condition_var_s vy_condition_var;
|
||||
|
||||
VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void);
|
||||
|
||||
VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var);
|
||||
|
||||
VY_DLLEXPORT void vyLockConditionVar(vy_condition_var *var);
|
||||
|
||||
VY_DLLEXPORT void vyUnlockConditionVar(vy_condition_var *var, bool signal);
|
||||
|
||||
/* The condition variable must be locked by the thread! */
|
||||
VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var);
|
||||
|
||||
typedef struct vy_thread_s vy_thread;
|
||||
|
||||
typedef void vy_thread_entry_fn(void *param);
|
||||
|
||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param);
|
||||
|
||||
VY_DLLEXPORT void vyJoinThread(vy_thread *thread);
|
||||
|
||||
#endif
|
||||
|
68
src/runtime/threading_cond.c
Normal file
68
src/runtime/threading_cond.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include "runtime.h"
|
||||
#include "threading.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <pthread.h>
|
||||
struct vy_condition_var_s {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
ptrdiff_t next_reusable;
|
||||
};
|
||||
|
||||
#define MAX_CONDS 1024
|
||||
vy_condition_var _conds[MAX_CONDS];
|
||||
static ptrdiff_t _first_reusable = MAX_CONDS;
|
||||
static ptrdiff_t _next = 0;
|
||||
static pthread_mutex_t _guard = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void) {
|
||||
pthread_mutex_lock(&_guard);
|
||||
if (_first_reusable < MAX_CONDS) {
|
||||
vy_condition_var *cond = &_conds[_first_reusable];
|
||||
_first_reusable = cond->next_reusable;
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return cond;
|
||||
} else if (_next < MAX_CONDS) {
|
||||
vy_condition_var *cond = &_conds[_next];
|
||||
if (pthread_mutex_init(&cond->mutex, NULL) != 0) {
|
||||
vyLog("core", "Condition variable creation failed");
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return NULL;
|
||||
}
|
||||
if (pthread_cond_init(&cond->cond, NULL) != 0) {
|
||||
vyLog("core", "Condition variable creation failed");
|
||||
}
|
||||
cond->next_reusable = MAX_CONDS;
|
||||
++_next;
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return cond;
|
||||
}
|
||||
vyReportError("core", "Ran out of condition variable objects");
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var) {
|
||||
ptrdiff_t index = var - &_conds[0];
|
||||
pthread_mutex_lock(&_guard);
|
||||
var->next_reusable = _first_reusable;
|
||||
_first_reusable = index;
|
||||
pthread_mutex_unlock(&_guard);
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyLockConditionVar(vy_condition_var *var) {
|
||||
pthread_mutex_lock(&var->mutex);
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyUnlockConditionVar(vy_condition_var *var, bool signal) {
|
||||
if (signal)
|
||||
pthread_cond_signal(&var->cond);
|
||||
pthread_mutex_unlock(&var->mutex);
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var) {
|
||||
pthread_cond_wait(&var->cond, &var->mutex);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#include "threading.h"
|
||||
#include "runtime.h"
|
||||
#include "threading.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -44,8 +44,7 @@ VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex) {
|
||||
VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
|
||||
return WaitForSingleObject(mutex->handle, INFINITE) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
|
||||
v VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
|
||||
return ReleaseMutex(mutex->handle) != 0;
|
||||
}
|
||||
|
||||
@ -61,30 +60,38 @@ struct vy_mutex_s {
|
||||
static vy_mutex _mutex[MAX_MUTEX];
|
||||
static ptrdiff_t _first_reusable = MAX_MUTEX;
|
||||
static ptrdiff_t _next = 0;
|
||||
static pthread_mutex_t _guard = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
|
||||
pthread_mutex_lock(&_guard);
|
||||
if (_first_reusable < MAX_MUTEX) {
|
||||
vy_mutex *mtx = &_mutex[_first_reusable];
|
||||
_first_reusable = mtx->next_reusable;
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return mtx;
|
||||
} else if (_next < MAX_MUTEX) {
|
||||
vy_mutex *mtx = &_mutex[_next];
|
||||
if (pthread_mutex_init(&mtx->handle, NULL) != 0) {
|
||||
vyLog("core", "Mutex creation failed");
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return NULL;
|
||||
}
|
||||
mtx->next_reusable = MAX_MUTEX;
|
||||
++_next;
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return mtx;
|
||||
}
|
||||
vyReportError("core", "Ran out of mutex objects");
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex) {
|
||||
ptrdiff_t index = mutex - &_mutex[0];
|
||||
ptrdiff_t index = mutex - &_mutex[0];
|
||||
pthread_mutex_lock(&_guard);
|
||||
mutex->next_reusable = _first_reusable;
|
||||
_first_reusable = index;
|
||||
pthread_mutex_unlock(&_guard);
|
||||
}
|
||||
|
||||
VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
|
74
src/runtime/threading_thread.c
Normal file
74
src/runtime/threading_thread.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include "runtime.h"
|
||||
#include "threading.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#elif defined(__linux__)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct vy_thread_s {
|
||||
pthread_t handle;
|
||||
ptrdiff_t next_reusable;
|
||||
|
||||
vy_thread_entry_fn *entry;
|
||||
void *param;
|
||||
|
||||
bool needs_join;
|
||||
};
|
||||
|
||||
#define MAX_THREADS 256
|
||||
static vy_thread _threads[MAX_THREADS];
|
||||
static ptrdiff_t _first_reusable = MAX_THREADS;
|
||||
static ptrdiff_t _next = 0;
|
||||
|
||||
static pthread_mutex_t _guard = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void *linuxThreadWrapper(void *arg) {
|
||||
vy_thread *user_thread = arg;
|
||||
user_thread->needs_join = false;
|
||||
user_thread->entry(user_thread->param);
|
||||
user_thread->needs_join = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param) {
|
||||
vy_thread *thrd = NULL;
|
||||
pthread_mutex_lock(&_guard);
|
||||
if (_first_reusable < MAX_THREADS) {
|
||||
thrd = &_threads[_first_reusable];
|
||||
_first_reusable = thrd->next_reusable;
|
||||
if (thrd->needs_join) {
|
||||
pthread_join(thrd->handle, NULL);
|
||||
thrd->needs_join = false;
|
||||
}
|
||||
} else if (_next < MAX_THREADS) {
|
||||
thrd = &_threads[_next];
|
||||
thrd->next_reusable = MAX_THREADS;
|
||||
++_next;
|
||||
}
|
||||
if (thrd) {
|
||||
thrd->entry = entry;
|
||||
thrd->param = param;
|
||||
if (pthread_create(&thrd->handle, NULL, linuxThreadWrapper, thrd) !=
|
||||
0) {
|
||||
vyLog("core", "Mutex creation failed");
|
||||
thrd = NULL;
|
||||
}
|
||||
} else {
|
||||
vyReportError("core", "Ran out of thread objects");
|
||||
}
|
||||
pthread_mutex_unlock(&_guard);
|
||||
return thrd;
|
||||
}
|
||||
|
||||
VY_DLLEXPORT void vyJoinThread(vy_thread *thread) {
|
||||
pthread_join(thread->handle, NULL);
|
||||
thread->needs_join = false;
|
||||
ptrdiff_t index = thread - &_threads[0];
|
||||
pthread_mutex_lock(&_guard);
|
||||
thread->next_reusable = _first_reusable;
|
||||
_first_reusable = index;
|
||||
pthread_mutex_unlock(&_guard);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user