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/threading.h',
 | 
				
			||||||
  'src/runtime/app.h',
 | 
					  'src/runtime/app.h',
 | 
				
			||||||
  'src/runtime/dynamic_libs.h',
 | 
					  'src/runtime/dynamic_libs.h',
 | 
				
			||||||
 | 
					  'src/runtime/jobs.h',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  'src/runtime/error_report.c',
 | 
					  'src/runtime/error_report.c',
 | 
				
			||||||
  'src/runtime/gfx_main.c',
 | 
					  'src/runtime/gfx_main.c',
 | 
				
			||||||
  'src/runtime/gfx_shader_loading.c',
 | 
					  'src/runtime/gfx_shader_loading.c',
 | 
				
			||||||
  'src/runtime/config.c',
 | 
					  'src/runtime/config.c',
 | 
				
			||||||
  'src/runtime/runtime_cvars.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/fio.c',
 | 
				
			||||||
  'src/runtime/app.c',
 | 
					  'src/runtime/app.c',
 | 
				
			||||||
  'src/runtime/dynamic_libs.c',
 | 
					  'src/runtime/dynamic_libs.c',
 | 
				
			||||||
 | 
					  'src/runtime/jobs.c',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Contrib Sources
 | 
					  # Contrib Sources
 | 
				
			||||||
  'contrib/xxhash/xxhash.c',
 | 
					  'contrib/xxhash/xxhash.c',
 | 
				
			||||||
@ -87,7 +91,7 @@ if vk_dep.found()
 | 
				
			|||||||
    # Contrib Sources
 | 
					    # Contrib Sources
 | 
				
			||||||
    'contrib/volk/volk.h',
 | 
					    'contrib/volk/volk.h',
 | 
				
			||||||
    'contrib/volk/volk.c',
 | 
					    'contrib/volk/volk.c',
 | 
				
			||||||
    dependencies : [m_dep, vk_inc_dep],
 | 
					    dependencies : [m_dep, vk_inc_dep, windowing_dep],
 | 
				
			||||||
    include_directories : incdir,
 | 
					    include_directories : incdir,
 | 
				
			||||||
    link_with : [runtime_lib],
 | 
					    link_with : [runtime_lib],
 | 
				
			||||||
    c_pch : 'pch/vk_pch.h',
 | 
					    c_pch : 'pch/vk_pch.h',
 | 
				
			||||||
 | 
				
			|||||||
@ -8,13 +8,14 @@
 | 
				
			|||||||
int WINAPI wWinMain(HINSTANCE hInstance,
 | 
					int WINAPI wWinMain(HINSTANCE hInstance,
 | 
				
			||||||
                    HINSTANCE hPrevInstance,
 | 
					                    HINSTANCE hPrevInstance,
 | 
				
			||||||
                    PWSTR pCmdLine,
 | 
					                    PWSTR pCmdLine,
 | 
				
			||||||
                    int nCmdShow) {    return vyWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
 | 
					                    int nCmdShow) {
 | 
				
			||||||
 | 
					    return vyWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined(__linux__)
 | 
					#elif defined(__linux__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv) {
 | 
					int main(int argc, char **argv) {
 | 
				
			||||||
    return 0;
 | 
					    return vyXlibEntry(argc, argv);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#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/gfx.h"
 | 
				
			||||||
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime/renderer_api.h"
 | 
					#include "runtime/renderer_api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,7 +17,7 @@ typedef struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static vy_pipeline_storage _storage;
 | 
					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 */
 | 
					    /* Search for free slot */
 | 
				
			||||||
    uint32_t slot = NUM_SLOTS;
 | 
					    uint32_t slot = NUM_SLOTS;
 | 
				
			||||||
    for (uint32_t i = 0; i < NUM_SLOTS; ++i) {
 | 
					    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) {
 | 
					    if (slot == NUM_SLOTS) {
 | 
				
			||||||
        vyReportError("GL_GFX", "Ran out of pipeline storage 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;
 | 
					    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.pipelines[slot]         = pipeline;
 | 
				
			||||||
    _storage.generation_in_use[slot] = (generation << 1) | 0x1;
 | 
					    _storage.generation_in_use[slot] = (generation << 1) | 0x1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_gfx_pipeline_id id;
 | 
					    vy_gfx_pipeline_handle id;
 | 
				
			||||||
    id.index = (generation << 27) | slot;
 | 
					    id.index = (generation << 27) | slot;
 | 
				
			||||||
    return id;
 | 
					    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 slot = id.index & 0x08ffffff;
 | 
				
			||||||
    uint32_t gen  = (id.index >> 27) & 0x1f;
 | 
					    uint32_t gen  = (id.index >> 27) & 0x1f;
 | 
				
			||||||
    if (slot >= NUM_SLOTS)
 | 
					    if (slot >= NUM_SLOTS)
 | 
				
			||||||
@ -52,7 +52,7 @@ static void ReleasePipelineSlot(vy_gfx_pipeline_id id) {
 | 
				
			|||||||
        _storage.generation_in_use[slot] &= ~0x1;
 | 
					        _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) {
 | 
					vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
    char info_log[512];
 | 
					    char info_log[512];
 | 
				
			||||||
@ -74,7 +74,7 @@ vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
 | 
				
			|||||||
                      info_log);
 | 
					                      info_log);
 | 
				
			||||||
        glDeleteProgram(prog);
 | 
					        glDeleteProgram(prog);
 | 
				
			||||||
        glDeleteShader(shader);
 | 
					        glDeleteShader(shader);
 | 
				
			||||||
        return (vy_gfx_pipeline_id){0};
 | 
					        return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    glAttachShader(prog, shader);
 | 
					    glAttachShader(prog, shader);
 | 
				
			||||||
    glLinkProgram(prog);
 | 
					    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);
 | 
					        vyReportError("GL_GFX", "Failed to link compute shader\n%s", info_log);
 | 
				
			||||||
        glDeleteShader(shader);
 | 
					        glDeleteShader(shader);
 | 
				
			||||||
        glDeleteProgram(prog);
 | 
					        glDeleteProgram(prog);
 | 
				
			||||||
        return (vy_gfx_pipeline_id){0};
 | 
					        return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    glDeleteShader(shader);
 | 
					    glDeleteShader(shader);
 | 
				
			||||||
    #endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_gl_pipeline pipeline;
 | 
					    vy_gl_pipeline pipeline;
 | 
				
			||||||
    pipeline.prog = 0;
 | 
					    pipeline.prog = 0;
 | 
				
			||||||
    return StorePipeline(pipeline);
 | 
					    return StorePipeline(pipeline);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_gfx_pipeline_id
 | 
					VY_DLLEXPORT vy_gfx_pipeline_handle
 | 
				
			||||||
vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
 | 
					vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #if 0
 | 
					#if 0
 | 
				
			||||||
    char info_log[512];
 | 
					    char info_log[512];
 | 
				
			||||||
    GLuint prog            = glCreateProgram();
 | 
					    GLuint prog            = glCreateProgram();
 | 
				
			||||||
    GLuint vertex_shader   = glCreateShader(GL_VERTEX_SHADER);
 | 
					    GLuint vertex_shader   = glCreateShader(GL_VERTEX_SHADER);
 | 
				
			||||||
@ -118,7 +118,7 @@ vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
 | 
				
			|||||||
        glDeleteShader(vertex_shader);
 | 
					        glDeleteShader(vertex_shader);
 | 
				
			||||||
        glDeleteShader(fragment_shader);
 | 
					        glDeleteShader(fragment_shader);
 | 
				
			||||||
        glDeleteProgram(prog);
 | 
					        glDeleteProgram(prog);
 | 
				
			||||||
        return (vy_gfx_pipeline_id){0};
 | 
					        return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    glAttachShader(prog, vertex_shader);
 | 
					    glAttachShader(prog, vertex_shader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -134,7 +134,7 @@ vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
 | 
				
			|||||||
        glDeleteShader(fragment_shader);
 | 
					        glDeleteShader(fragment_shader);
 | 
				
			||||||
        glDeleteShader(fragment_shader);
 | 
					        glDeleteShader(fragment_shader);
 | 
				
			||||||
        glDeleteProgram(prog);
 | 
					        glDeleteProgram(prog);
 | 
				
			||||||
        return (vy_gfx_pipeline_id){0};
 | 
					        return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    glAttachShader(prog, fragment_shader);
 | 
					    glAttachShader(prog, fragment_shader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -146,12 +146,12 @@ vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
 | 
				
			|||||||
        glDeleteShader(vertex_shader);
 | 
					        glDeleteShader(vertex_shader);
 | 
				
			||||||
        glDeleteShader(fragment_shader);
 | 
					        glDeleteShader(fragment_shader);
 | 
				
			||||||
        glDeleteProgram(prog);
 | 
					        glDeleteProgram(prog);
 | 
				
			||||||
        return (vy_gfx_pipeline_id){0};
 | 
					        return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    glDeleteShader(vertex_shader);
 | 
					    glDeleteShader(vertex_shader);
 | 
				
			||||||
    glDeleteShader(fragment_shader);
 | 
					    glDeleteShader(fragment_shader);
 | 
				
			||||||
    #endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_gl_pipeline pipeline;
 | 
					    vy_gl_pipeline pipeline;
 | 
				
			||||||
    pipeline.prog = 0;
 | 
					    pipeline.prog = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -92,11 +92,11 @@ VY_DLLEXPORT void vyRegisterCVars(void) {
 | 
				
			|||||||
    vyRegisterCVAR(&r_VkPreferMailboxMode);
 | 
					    vyRegisterCVAR(&r_VkPreferMailboxMode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int CreateInstance(void) {
 | 
					static vy_result CreateInstance(void) {
 | 
				
			||||||
    VkResult result = volkInitialize();
 | 
					    VkResult result = volkInitialize();
 | 
				
			||||||
    if (result != VK_SUCCESS) {
 | 
					    if (result != VK_SUCCESS) {
 | 
				
			||||||
        vyReportError("vk", "Initialization failed: volkInitialize()");
 | 
					        vyReportError("vk", "Initialization failed: volkInitialize()");
 | 
				
			||||||
        return 0;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    VkApplicationInfo app_info = {
 | 
					    VkApplicationInfo app_info = {
 | 
				
			||||||
@ -160,7 +160,7 @@ static int CreateInstance(void) {
 | 
				
			|||||||
    result = vkCreateInstance(&instance_info, g_gpu.alloc_cb, &g_gpu.instance);
 | 
					    result = vkCreateInstance(&instance_info, g_gpu.alloc_cb, &g_gpu.instance);
 | 
				
			||||||
    if (result != VK_SUCCESS) {
 | 
					    if (result != VK_SUCCESS) {
 | 
				
			||||||
        vyReportError("vk", "Failed to create the vulkan instance.");
 | 
					        vyReportError("vk", "Failed to create the vulkan instance.");
 | 
				
			||||||
        return -1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    volkLoadInstance(g_gpu.instance);
 | 
					    volkLoadInstance(g_gpu.instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -179,10 +179,10 @@ static int CreateInstance(void) {
 | 
				
			|||||||
                                   g_gpu.alloc_cb,
 | 
					                                   g_gpu.alloc_cb,
 | 
				
			||||||
                                   &g_gpu.messenger);
 | 
					                                   &g_gpu.messenger);
 | 
				
			||||||
#endif
 | 
					#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
 | 
					#ifdef _WIN32
 | 
				
			||||||
    g_gpu.native_window.hInstance            = info->hInstance;
 | 
					    g_gpu.native_window.hInstance            = info->hInstance;
 | 
				
			||||||
    g_gpu.native_window.hWnd                 = info->hWnd;
 | 
					    g_gpu.native_window.hWnd                 = info->hWnd;
 | 
				
			||||||
@ -195,24 +195,24 @@ static int CreateSurface(const vy_renderer_init_info *info) {
 | 
				
			|||||||
                                &surface_info,
 | 
					                                &surface_info,
 | 
				
			||||||
                                g_gpu.alloc_cb,
 | 
					                                g_gpu.alloc_cb,
 | 
				
			||||||
                                &g_gpu.surface) == VK_SUCCESS)
 | 
					                                &g_gpu.surface) == VK_SUCCESS)
 | 
				
			||||||
        return 0;
 | 
					        return VY_SUCCESS;
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        return -100;
 | 
					        return 100;
 | 
				
			||||||
#elif defined(VY_USE_XLIB_KHR)
 | 
					#elif defined(VY_USE_XLIB_KHR)
 | 
				
			||||||
    g_gpu.native_window.display             = info->display;
 | 
					    g_gpu.native_window.display             = info->display;
 | 
				
			||||||
    g_gpu.native_window.window              = info->window;
 | 
					    g_gpu.native_window.window              = info->window;
 | 
				
			||||||
    VkXlibSurfaceCreateInfoKHR surface_info = {
 | 
					    VkXlibSurfaceCreateInfoKHR surface_info = {
 | 
				
			||||||
        .sType     = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
 | 
					        .sType  = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
 | 
				
			||||||
        .dpy       = info->display,
 | 
					        .dpy    = info->display,
 | 
				
			||||||
        .window    = info->window,
 | 
					        .window = info->window,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    if (vkCreateXlibSurfaceKHR(g_gpu.instance,
 | 
					    if (vkCreateXlibSurfaceKHR(g_gpu.instance,
 | 
				
			||||||
                               &surface_info,
 | 
					                               &surface_info,
 | 
				
			||||||
                               &g_gpu.alloc_cb,
 | 
					                               &g_gpu.alloc_cb,
 | 
				
			||||||
                               &g_gpu.surface) == VK_SUCCESS)
 | 
					                               &g_gpu.surface) == VK_SUCCESS)
 | 
				
			||||||
        return 0;
 | 
					        return VY_SUCCESS;
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        return -100;
 | 
					        return 100;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -222,7 +222,8 @@ typedef struct {
 | 
				
			|||||||
    uint32_t present;
 | 
					    uint32_t present;
 | 
				
			||||||
} vy_queue_indices;
 | 
					} 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,
 | 
					    vy_queue_indices indices = {.graphics = UINT32_MAX,
 | 
				
			||||||
                                .compute  = UINT32_MAX,
 | 
					                                .compute  = UINT32_MAX,
 | 
				
			||||||
                                .present  = UINT32_MAX};
 | 
					                                .present  = UINT32_MAX};
 | 
				
			||||||
@ -242,7 +243,7 @@ static vy_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev, VkSurfac
 | 
				
			|||||||
            indices.graphics = i;
 | 
					            indices.graphics = i;
 | 
				
			||||||
        if ((props[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0)
 | 
					        if ((props[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0)
 | 
				
			||||||
            indices.compute = i;
 | 
					            indices.compute = i;
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
        VkBool32 present_supported = VK_FALSE;
 | 
					        VkBool32 present_supported = VK_FALSE;
 | 
				
			||||||
        vkGetPhysicalDeviceSurfaceSupportKHR(phys_dev,
 | 
					        vkGetPhysicalDeviceSurfaceSupportKHR(phys_dev,
 | 
				
			||||||
                                             i,
 | 
					                                             i,
 | 
				
			||||||
@ -297,8 +298,7 @@ out:
 | 
				
			|||||||
    return supported;
 | 
					    return supported;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ChoosePhysicalDevice(void) {
 | 
					static vy_result ChoosePhysicalDevice(void) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_gpu.phys_device          = VK_NULL_HANDLE;
 | 
					    g_gpu.phys_device          = VK_NULL_HANDLE;
 | 
				
			||||||
    uint32_t phys_device_count = 0;
 | 
					    uint32_t phys_device_count = 0;
 | 
				
			||||||
@ -306,7 +306,7 @@ static int ChoosePhysicalDevice(void) {
 | 
				
			|||||||
        vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, NULL);
 | 
					        vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, NULL);
 | 
				
			||||||
    if (result != VK_SUCCESS) {
 | 
					    if (result != VK_SUCCESS) {
 | 
				
			||||||
        vyReportError("vk", "Failed to enumerate the physical devices.");
 | 
					        vyReportError("vk", "Failed to enumerate the physical devices.");
 | 
				
			||||||
        return -2;
 | 
					        return 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    VkPhysicalDevice *phys_devices =
 | 
					    VkPhysicalDevice *phys_devices =
 | 
				
			||||||
        calloc(phys_device_count, sizeof(VkPhysicalDevice));
 | 
					        calloc(phys_device_count, sizeof(VkPhysicalDevice));
 | 
				
			||||||
@ -314,15 +314,14 @@ static int ChoosePhysicalDevice(void) {
 | 
				
			|||||||
        vyReportError(
 | 
					        vyReportError(
 | 
				
			||||||
            "vk",
 | 
					            "vk",
 | 
				
			||||||
            "Failed to enumerate the physical devices: Out of memory.");
 | 
					            "Failed to enumerate the physical devices: Out of memory.");
 | 
				
			||||||
        return -2;
 | 
					        return 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vkEnumeratePhysicalDevices(g_gpu.instance,
 | 
					    vkEnumeratePhysicalDevices(g_gpu.instance,
 | 
				
			||||||
                               &phys_device_count,
 | 
					                               &phys_device_count,
 | 
				
			||||||
                               phys_devices);
 | 
					                               phys_devices);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    uint32_t highscore  = 0;
 | 
				
			||||||
    uint32_t highscore = 0;
 | 
					    uint32_t best_index = phys_device_count;
 | 
				
			||||||
    uint32_t best_index = phys_device_count; 
 | 
					 | 
				
			||||||
    for (uint32_t i = 0; i < phys_device_count; ++i) {
 | 
					    for (uint32_t i = 0; i < phys_device_count; ++i) {
 | 
				
			||||||
        VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props = {
 | 
					        VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props = {
 | 
				
			||||||
            .sType =
 | 
					            .sType =
 | 
				
			||||||
@ -362,7 +361,7 @@ static int ChoosePhysicalDevice(void) {
 | 
				
			|||||||
                     : 0;
 | 
					                     : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (score > highscore) {
 | 
					        if (score > highscore) {
 | 
				
			||||||
            highscore = score;
 | 
					            highscore  = score;
 | 
				
			||||||
            best_index = i;
 | 
					            best_index = i;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -392,12 +391,12 @@ static int ChoosePhysicalDevice(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (g_gpu.phys_device == VK_NULL_HANDLE) {
 | 
					    if (g_gpu.phys_device == VK_NULL_HANDLE) {
 | 
				
			||||||
        vyReportError("vk", "Failed to find a suitable physical device.");
 | 
					        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[] = {
 | 
					    const char *extensions[] = {
 | 
				
			||||||
        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
 | 
					        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@ -432,15 +431,14 @@ static int CreateDevice(void) {
 | 
				
			|||||||
        queue_indices.present != queue_indices.compute) {
 | 
					        queue_indices.present != queue_indices.compute) {
 | 
				
			||||||
        queue_info[distinct_queue_count].sType =
 | 
					        queue_info[distinct_queue_count].sType =
 | 
				
			||||||
            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 | 
					            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 | 
				
			||||||
        queue_info[distinct_queue_count].pNext                         = NULL;
 | 
					        queue_info[distinct_queue_count].pNext      = NULL;
 | 
				
			||||||
        queue_info[distinct_queue_count].flags = 0;
 | 
					        queue_info[distinct_queue_count].flags      = 0;
 | 
				
			||||||
        queue_info[distinct_queue_count].queueCount = 1;
 | 
					        queue_info[distinct_queue_count].queueCount = 1;
 | 
				
			||||||
        queue_info[distinct_queue_count].queueFamilyIndex =
 | 
					        queue_info[distinct_queue_count].queueFamilyIndex =
 | 
				
			||||||
            queue_indices.present;
 | 
					            queue_indices.present;
 | 
				
			||||||
        queue_info[distinct_queue_count].pQueuePriorities = &priority;
 | 
					        queue_info[distinct_queue_count].pQueuePriorities = &priority;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    VkDeviceCreateInfo device_info = {
 | 
					    VkDeviceCreateInfo device_info = {
 | 
				
			||||||
        .sType                   = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
 | 
					        .sType                   = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
 | 
				
			||||||
        .enabledExtensionCount   = VY_ARRAY_COUNT(extensions),
 | 
					        .enabledExtensionCount   = VY_ARRAY_COUNT(extensions),
 | 
				
			||||||
@ -453,7 +451,7 @@ static int CreateDevice(void) {
 | 
				
			|||||||
                       g_gpu.alloc_cb,
 | 
					                       g_gpu.alloc_cb,
 | 
				
			||||||
                       &g_gpu.device) != VK_SUCCESS) {
 | 
					                       &g_gpu.device) != VK_SUCCESS) {
 | 
				
			||||||
        vyReportError("vk", "Device creation failed.");
 | 
					        vyReportError("vk", "Device creation failed.");
 | 
				
			||||||
        return -10;
 | 
					        return 10;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vkGetDeviceQueue(g_gpu.device,
 | 
					    vkGetDeviceQueue(g_gpu.device,
 | 
				
			||||||
@ -469,10 +467,10 @@ static int CreateDevice(void) {
 | 
				
			|||||||
                     0,
 | 
					                     0,
 | 
				
			||||||
                     &g_gpu.present_queue);
 | 
					                     &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");
 | 
					    vyLog("vk", "Init");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _tracking_alloc_cbs.pUserData       = NULL;
 | 
					    _tracking_alloc_cbs.pUserData       = NULL;
 | 
				
			||||||
@ -487,22 +485,22 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int res = CreateInstance();
 | 
					    int res = CreateInstance();
 | 
				
			||||||
    if (res != 0)
 | 
					    if (res != VY_SUCCESS)
 | 
				
			||||||
        return res;
 | 
					        return res;
 | 
				
			||||||
    res = CreateSurface(info);
 | 
					    res = CreateSurface(info);
 | 
				
			||||||
    if (res != 0)
 | 
					    if (res != VY_SUCCESS)
 | 
				
			||||||
        return res;
 | 
					        return res;
 | 
				
			||||||
    res = ChoosePhysicalDevice();
 | 
					    res = ChoosePhysicalDevice();
 | 
				
			||||||
    if (res != 0)
 | 
					    if (res != VY_SUCCESS)
 | 
				
			||||||
        return res;
 | 
					        return res;
 | 
				
			||||||
    res = CreateDevice();
 | 
					    res = CreateDevice();
 | 
				
			||||||
    if (res != 0)
 | 
					    if (res != VY_SUCCESS)
 | 
				
			||||||
        return res;
 | 
					        return res;
 | 
				
			||||||
    res = vyCreateSwapchain();
 | 
					    res = vyCreateSwapchain();
 | 
				
			||||||
    if (res != 0)
 | 
					    if (res != VY_SUCCESS)
 | 
				
			||||||
        return res;
 | 
					        return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyShutdown(void) {
 | 
					VY_DLLEXPORT void vyShutdown(void) {
 | 
				
			||||||
 | 
				
			|||||||
@ -7,10 +7,10 @@
 | 
				
			|||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
#define WIN32_LEAN_AND_MEAN
 | 
					    #define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
#include <Windows.h>
 | 
					    #include <Windows.h>
 | 
				
			||||||
#elif defined(VY_USE_XLIB)
 | 
					#elif defined(VY_USE_XLIB)
 | 
				
			||||||
#include <X11/Xlib.h>
 | 
					    #include <X11/Xlib.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_CVAR_I(r_VkPreferredSwapchainImages,
 | 
					VY_CVAR_I(r_VkPreferredSwapchainImages,
 | 
				
			||||||
@ -55,7 +55,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
    params.surface_format = formats[0];
 | 
					    params.surface_format = formats[0];
 | 
				
			||||||
    for (uint32_t i = 0; i < format_count; ++i) {
 | 
					    for (uint32_t i = 0; i < format_count; ++i) {
 | 
				
			||||||
        if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
 | 
					        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];
 | 
					            params.surface_format = formats[i];
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -72,14 +72,14 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
        RECT client_area;
 | 
					        RECT client_area;
 | 
				
			||||||
        GetClientRect(g_gpu.native_window.hWnd, &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;
 | 
					        params.extent.height = (uint32_t)client_area.bottom;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        XWindowAttributes attribs;
 | 
					        XWindowAttributes attribs;
 | 
				
			||||||
        XGetWindowAttributes(g_gpu.native_window.display,
 | 
					        XGetWindowAttributes(g_gpu.native_window.display,
 | 
				
			||||||
                             g_gpu.native_window.window,
 | 
					                             g_gpu.native_window.window,
 | 
				
			||||||
                             &attribs);
 | 
					                             &attribs);
 | 
				
			||||||
        params.extent.width = (uint32_t)attribs.width;
 | 
					        params.extent.width  = (uint32_t)attribs.width;
 | 
				
			||||||
        params.extent.height = (uint32_t)attribs.height;
 | 
					        params.extent.height = (uint32_t)attribs.height;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -90,7 +90,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
vy_swapchain g_swapchain;
 | 
					vy_swapchain g_swapchain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vyCreateSwapchain(void) {
 | 
					vy_result vyCreateSwapchain(void) {
 | 
				
			||||||
    vy_device_swapchain_parameters device_params =
 | 
					    vy_device_swapchain_parameters device_params =
 | 
				
			||||||
        DetermineSwapchainParameters();
 | 
					        DetermineSwapchainParameters();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -117,22 +117,21 @@ int vyCreateSwapchain(void) {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    uint32_t queue_families[] = {g_gpu.graphics_family, g_gpu.present_family};
 | 
					    uint32_t queue_families[] = {g_gpu.graphics_family, g_gpu.present_family};
 | 
				
			||||||
    if (g_gpu.present_family != g_gpu.graphics_family) {
 | 
					    if (g_gpu.present_family != g_gpu.graphics_family) {
 | 
				
			||||||
        swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
 | 
					        swapchain_info.imageSharingMode      = VK_SHARING_MODE_CONCURRENT;
 | 
				
			||||||
        swapchain_info.pQueueFamilyIndices = queue_families;
 | 
					        swapchain_info.pQueueFamilyIndices   = queue_families;
 | 
				
			||||||
        swapchain_info.queueFamilyIndexCount = 2;
 | 
					        swapchain_info.queueFamilyIndexCount = 2;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
 | 
					        swapchain_info.imageSharingMode      = VK_SHARING_MODE_EXCLUSIVE;
 | 
				
			||||||
        swapchain_info.pQueueFamilyIndices   = NULL;
 | 
					        swapchain_info.pQueueFamilyIndices   = NULL;
 | 
				
			||||||
        swapchain_info.queueFamilyIndexCount = 0;
 | 
					        swapchain_info.queueFamilyIndexCount = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (vkCreateSwapchainKHR(g_gpu.device,
 | 
					    if (vkCreateSwapchainKHR(g_gpu.device,
 | 
				
			||||||
                             &swapchain_info,
 | 
					                             &swapchain_info,
 | 
				
			||||||
                             g_gpu.alloc_cb,
 | 
					                             g_gpu.alloc_cb,
 | 
				
			||||||
                             &g_swapchain.swapchain) != VK_SUCCESS) {
 | 
					                             &g_swapchain.swapchain) != VK_SUCCESS) {
 | 
				
			||||||
        vyReportError("vk", "Failed to create the swapchain");
 | 
					        vyReportError("vk", "Failed to create the swapchain");
 | 
				
			||||||
        return -50;
 | 
					        return 50;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    g_swapchain.format = device_params.surface_format.format;
 | 
					    g_swapchain.format = device_params.surface_format.format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -146,7 +145,7 @@ int vyCreateSwapchain(void) {
 | 
				
			|||||||
        vyReportError("vk",
 | 
					        vyReportError("vk",
 | 
				
			||||||
                      "Unsupported number of swapchain images: %u",
 | 
					                      "Unsupported number of swapchain images: %u",
 | 
				
			||||||
                      g_swapchain.image_count);
 | 
					                      g_swapchain.image_count);
 | 
				
			||||||
        return -51;
 | 
					        return 51;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
					    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
				
			||||||
                            g_swapchain.swapchain,
 | 
					                            g_swapchain.swapchain,
 | 
				
			||||||
@ -156,37 +155,44 @@ int vyCreateSwapchain(void) {
 | 
				
			|||||||
    /* Create image views */
 | 
					    /* Create image views */
 | 
				
			||||||
    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
					    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
				
			||||||
        VkImageViewCreateInfo view_info = {
 | 
					        VkImageViewCreateInfo view_info = {
 | 
				
			||||||
            .sType  = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
 | 
					            .sType    = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
 | 
				
			||||||
            .image  = g_swapchain.images[i],
 | 
					            .image    = g_swapchain.images[i],
 | 
				
			||||||
            .format = g_swapchain.format,
 | 
					            .format   = g_swapchain.format,
 | 
				
			||||||
            .viewType = VK_IMAGE_VIEW_TYPE_2D,
 | 
					            .viewType = VK_IMAGE_VIEW_TYPE_2D,
 | 
				
			||||||
            .components = {
 | 
					            .components =
 | 
				
			||||||
                .r = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
					                {
 | 
				
			||||||
                .g = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
					                             .r = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
				
			||||||
                .b = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
					                             .g = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
				
			||||||
                .a = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
					                             .b = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
				
			||||||
            },
 | 
					                             .a = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
				
			||||||
            .subresourceRange = {
 | 
					                             },
 | 
				
			||||||
                .aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT,
 | 
					            .subresourceRange =
 | 
				
			||||||
                .baseArrayLayer = 0,
 | 
					                {
 | 
				
			||||||
                .layerCount     = 1,
 | 
					                             .aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT,
 | 
				
			||||||
                .baseMipLevel   = 0,
 | 
					                             .baseArrayLayer = 0,
 | 
				
			||||||
                .levelCount     = 1,
 | 
					                             .layerCount     = 1,
 | 
				
			||||||
            },
 | 
					                             .baseMipLevel   = 0,
 | 
				
			||||||
 | 
					                             .levelCount     = 1,
 | 
				
			||||||
 | 
					                             },
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        if (vkCreateImageView(g_gpu.device,
 | 
					        if (vkCreateImageView(g_gpu.device,
 | 
				
			||||||
                          &view_info,
 | 
					                              &view_info,
 | 
				
			||||||
                          g_gpu.alloc_cb,
 | 
					                              g_gpu.alloc_cb,
 | 
				
			||||||
                              &g_swapchain.image_views[i]) != VK_SUCCESS) {
 | 
					                              &g_swapchain.image_views[i]) != VK_SUCCESS) {
 | 
				
			||||||
            vyReportError("vk",
 | 
					            vyReportError("vk",
 | 
				
			||||||
                          "Failed to create an image view for the swapchain.");
 | 
					                          "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) {
 | 
					void vyDestroySwapchain(void) {
 | 
				
			||||||
    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
					    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
				
			||||||
@ -195,4 +201,4 @@ void vyDestroySwapchain(void) {
 | 
				
			|||||||
                           g_gpu.alloc_cb);
 | 
					                           g_gpu.alloc_cb);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vkDestroySwapchainKHR(g_gpu.device, g_swapchain.swapchain, g_gpu.alloc_cb);
 | 
					    vkDestroySwapchainKHR(g_gpu.device, g_swapchain.swapchain, g_gpu.alloc_cb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <volk/volk.h>
 | 
					#include <volk/volk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VY_VK_MAX_SWAPCHAIN_IMAGES 3
 | 
					#define VY_VK_MAX_SWAPCHAIN_IMAGES 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
@ -17,7 +19,9 @@ typedef struct {
 | 
				
			|||||||
extern vy_swapchain g_swapchain;
 | 
					extern vy_swapchain g_swapchain;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int vyCreateSwapchain(void);
 | 
					vy_result vyCreateSwapchain(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyRecreateSwapchain(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void vyDestroySwapchain(void);
 | 
					void vyDestroySwapchain(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
#include "app.h"
 | 
					#include "app.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "fio.h"
 | 
					#include "fio.h"
 | 
				
			||||||
#include "gfx.h"
 | 
					#include "gfx.h"
 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#include "renderer_api.h"
 | 
					#include "renderer_api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void __RegisterRuntimeCVars(void);
 | 
					extern void __RegisterRuntimeCVars(void);
 | 
				
			||||||
@ -11,15 +11,15 @@ VY_CVAR_I(rt_WindowWidth, "Window width. Default: 1024", 1024);
 | 
				
			|||||||
VY_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
 | 
					VY_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
#define WIN32_LEAN_AND_MEAN
 | 
					    #define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
#include <Windows.h>
 | 
					    #include <Windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static LRESULT CALLBACK win32WndProc(HWND hWnd,
 | 
					static LRESULT CALLBACK win32WndProc(HWND hWnd,
 | 
				
			||||||
                                     UINT uMsg,
 | 
					                                     UINT uMsg,
 | 
				
			||||||
                                     WPARAM wParam,
 | 
					                                     WPARAM wParam,
 | 
				
			||||||
                                     LPARAM lParam) {
 | 
					                                     LPARAM lParam) {
 | 
				
			||||||
    switch (uMsg) {
 | 
					    switch (uMsg) {
 | 
				
			||||||
    case WM_CLOSE: 
 | 
					    case WM_CLOSE:
 | 
				
			||||||
        PostQuitMessage(0);
 | 
					        PostQuitMessage(0);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
@ -28,9 +28,9 @@ static LRESULT CALLBACK win32WndProc(HWND hWnd,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
					VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
				
			||||||
    HINSTANCE hPrevInstance,
 | 
					                              HINSTANCE hPrevInstance,
 | 
				
			||||||
    PWSTR pCmdLine,
 | 
					                              PWSTR pCmdLine,
 | 
				
			||||||
    int nCmdShow) {
 | 
					                              int nCmdShow) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __RegisterRuntimeCVars();
 | 
					    __RegisterRuntimeCVars();
 | 
				
			||||||
    vyRegisterRendererCVars();
 | 
					    vyRegisterRendererCVars();
 | 
				
			||||||
@ -43,7 +43,6 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
				
			|||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    WNDCLASSEXW wndclass = {
 | 
					    WNDCLASSEXW wndclass = {
 | 
				
			||||||
        .cbSize        = sizeof(wndclass),
 | 
					        .cbSize        = sizeof(wndclass),
 | 
				
			||||||
        .hInstance     = hInstance,
 | 
					        .hInstance     = hInstance,
 | 
				
			||||||
@ -56,12 +55,12 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
				
			|||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HWND wnd = NULL; 
 | 
					    HWND wnd = NULL;
 | 
				
			||||||
    if (rt_Fullscreen.i) {
 | 
					    if (rt_Fullscreen.i) {
 | 
				
			||||||
        /* Fullscreen window */
 | 
					        /* Fullscreen window */
 | 
				
			||||||
        int w    = GetSystemMetrics(SM_CXSCREEN);
 | 
					        int w = GetSystemMetrics(SM_CXSCREEN);
 | 
				
			||||||
        int h    = GetSystemMetrics(SM_CYSCREEN);
 | 
					        int h = GetSystemMetrics(SM_CYSCREEN);
 | 
				
			||||||
        wnd      = CreateWindowExW(WS_EX_APPWINDOW,
 | 
					        wnd   = CreateWindowExW(WS_EX_APPWINDOW,
 | 
				
			||||||
                              L"vyWndClass",
 | 
					                              L"vyWndClass",
 | 
				
			||||||
                              L"Voyage",
 | 
					                              L"Voyage",
 | 
				
			||||||
                              WS_POPUP,
 | 
					                              WS_POPUP,
 | 
				
			||||||
@ -121,10 +120,135 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vyShutdownGFX();
 | 
					    vyShutdownGFX();
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    DestroyWindow(wnd);
 | 
					    DestroyWindow(wnd);
 | 
				
			||||||
    UnregisterClassW(L"vyWndClass", hInstance);
 | 
					    UnregisterClassW(L"vyWndClass", hInstance);
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
 | 
					    vyShutdownFIO();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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();
 | 
					    vyShutdownFIO();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -11,9 +11,13 @@
 | 
				
			|||||||
struct HINSTANCE__;
 | 
					struct HINSTANCE__;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT int vyWin32Entry(struct HINSTANCE__ *hInstance,
 | 
					VY_DLLEXPORT int vyWin32Entry(struct HINSTANCE__ *hInstance,
 | 
				
			||||||
                 struct HINSTANCE__ *hPrevInstance,
 | 
					                              struct HINSTANCE__ *hPrevInstance,
 | 
				
			||||||
                 wchar_t *pCmdLine,
 | 
					                              wchar_t *pCmdLine,
 | 
				
			||||||
                 int nCmdShow);
 | 
					                              int nCmdShow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(VY_USE_XLIB)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VY_DLLEXPORT int vyXlibEntry(int argc, char **argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,9 +4,13 @@
 | 
				
			|||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    #define VY_DLLNAME(s) (s".dll")
 | 
					    #define VY_DLLNAME(s)                                                      \
 | 
				
			||||||
 | 
					        (".\\"s                                                                \
 | 
				
			||||||
 | 
					         ".dll")
 | 
				
			||||||
#elif defined(__linux__)
 | 
					#elif defined(__linux__)
 | 
				
			||||||
    #define VY_DLLNAME(s) ("lib"s".so")
 | 
					    #define VY_DLLNAME(s)                                                      \
 | 
				
			||||||
 | 
					        ("./lib"s                                                              \
 | 
				
			||||||
 | 
					         ".so")
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void *vy_dynlib;
 | 
					typedef void *vy_dynlib;
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,7 @@ static vy_file_tab _file_tab;
 | 
				
			|||||||
#ifdef __linux__
 | 
					#ifdef __linux__
 | 
				
			||||||
static pthread_t _thread;
 | 
					static pthread_t _thread;
 | 
				
			||||||
#elif defined(_WIN32)
 | 
					#elif defined(_WIN32)
 | 
				
			||||||
static HANDLE _fio_thread = NULL;
 | 
					static HANDLE _fio_thread     = NULL;
 | 
				
			||||||
static HANDLE _fio_term_event = NULL;
 | 
					static HANDLE _fio_term_event = NULL;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -91,7 +91,7 @@ static void ShutdownFIOQueue(void) {
 | 
				
			|||||||
#ifdef __linux__
 | 
					#ifdef __linux__
 | 
				
			||||||
    pthread_cond_destroy(&_queue.pending_cond);
 | 
					    pthread_cond_destroy(&_queue.pending_cond);
 | 
				
			||||||
    pthread_mutex_destroy(&_queue.mutex);
 | 
					    pthread_mutex_destroy(&_queue.mutex);
 | 
				
			||||||
#elif defined(_WIN32)  
 | 
					#elif defined(_WIN32)
 | 
				
			||||||
    DeleteCriticalSection(&_queue.critical_section);
 | 
					    DeleteCriticalSection(&_queue.critical_section);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -173,7 +173,7 @@ VY_DLLEXPORT void vyShutdownFIO(void) {
 | 
				
			|||||||
    if (SetEvent(_fio_term_event)) {
 | 
					    if (SetEvent(_fio_term_event)) {
 | 
				
			||||||
        WakeAllConditionVariable(&_queue.pending_cond);
 | 
					        WakeAllConditionVariable(&_queue.pending_cond);
 | 
				
			||||||
        WaitForSingleObject(_fio_thread, INFINITE);
 | 
					        WaitForSingleObject(_fio_thread, INFINITE);
 | 
				
			||||||
        CloseHandle(_fio_thread);   
 | 
					        CloseHandle(_fio_thread);
 | 
				
			||||||
        CloseHandle(_fio_term_event);
 | 
					        CloseHandle(_fio_term_event);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        vyReportError("FIO", "Failed to signal the termination event.");
 | 
					        vyReportError("FIO", "Failed to signal the termination event.");
 | 
				
			||||||
@ -406,8 +406,8 @@ static void ProcessRead(vy_file_op *op) {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    op->buffer.data = NULL;
 | 
					    op->buffer.data  = NULL;
 | 
				
			||||||
    op->buffer.size = 0;
 | 
					    op->buffer.size  = 0;
 | 
				
			||||||
    op->buffer.flags = 0;
 | 
					    op->buffer.flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FILE *file = fopen(path, "rb");
 | 
					    FILE *file = fopen(path, "rb");
 | 
				
			||||||
@ -424,8 +424,8 @@ static void ProcessRead(vy_file_op *op) {
 | 
				
			|||||||
    op->buffer.size = (size_t)fsz;
 | 
					    op->buffer.size = (size_t)fsz;
 | 
				
			||||||
    if (fread(op->buffer.data, fsz, 1, file) != 1) {
 | 
					    if (fread(op->buffer.data, fsz, 1, file) != 1) {
 | 
				
			||||||
        free(op->buffer.data);
 | 
					        free(op->buffer.data);
 | 
				
			||||||
        op->buffer.data = NULL;
 | 
					        op->buffer.data  = NULL;
 | 
				
			||||||
        op->buffer.size = 0;
 | 
					        op->buffer.size  = 0;
 | 
				
			||||||
        op->buffer.flags = VY_FILE_BUFFER_FLAG_READ_FAILED;
 | 
					        op->buffer.flags = VY_FILE_BUFFER_FLAG_READ_FAILED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -475,4 +475,4 @@ static DWORD WINAPI win32FIOThreadProc(_In_ LPVOID lpParam) {
 | 
				
			|||||||
    vyLog("FIO", "Exit FIO thread");
 | 
					    vyLog("FIO", "Exit FIO thread");
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -7,8 +7,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum
 | 
					enum {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    VY_FILE_BUFFER_FLAG_FILE_NOT_FOUND = 0x1,
 | 
					    VY_FILE_BUFFER_FLAG_FILE_NOT_FOUND = 0x1,
 | 
				
			||||||
    VY_FILE_BUFFER_FLAG_READ_FAILED    = 0x2,
 | 
					    VY_FILE_BUFFER_FLAG_READ_FAILED    = 0x2,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -19,7 +18,7 @@ typedef struct {
 | 
				
			|||||||
    uint32_t flags;
 | 
					    uint32_t flags;
 | 
				
			||||||
} vy_file_buffer;
 | 
					} vy_file_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline bool vyWasFileBufferSuccessful(const vy_file_buffer *fb) {
 | 
					static inline bool vyWasFileBufferSuccessful(const vy_file_buffer *fb) {
 | 
				
			||||||
    return fb->flags == 0;
 | 
					    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 vyIsFIOFinished(vy_fio_handle fio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT bool vyRetrieveReadBuffer(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);
 | 
					VY_DLLEXPORT void vyFreeFileBuffer(vy_file_buffer buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,8 +9,8 @@
 | 
				
			|||||||
 * - object renderer (for static models)
 | 
					 * - object renderer (for static models)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,12 +23,11 @@ VY_DLLEXPORT bool vyInitGFX(vy_renderer_init_info *renderer_info);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyShutdownGFX(void);
 | 
					VY_DLLEXPORT void vyShutdownGFX(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Generational indices for backend objects */
 | 
					/* Handles backend objects */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    uint32_t index;
 | 
					    uint32_t index;
 | 
				
			||||||
} vy_gfx_pipeline_id;
 | 
					} vy_gfx_pipeline_handle;
 | 
				
			||||||
 | 
					 | 
				
			||||||
#define VY_IS_GFX_ID_VALID(id) ((id).index != 0)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
					/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
				
			||||||
 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
					 * 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 *storage_bindings;
 | 
				
			||||||
    vy_attribute_binding *texture_bindings;
 | 
					    vy_attribute_binding *texture_bindings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_gfx_pipeline_id pipeline;
 | 
					    vy_gfx_pipeline_handle pipeline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned int uniform_binding_count;
 | 
					    unsigned int uniform_binding_count;
 | 
				
			||||||
    unsigned int storage_binding_count;
 | 
					    unsigned int storage_binding_count;
 | 
				
			||||||
 | 
				
			|||||||
@ -2,10 +2,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define VY_DONT_DEFINE_RENDERER_GLOBAL
 | 
					#define VY_DONT_DEFINE_RENDERER_GLOBAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gfx.h"
 | 
					 | 
				
			||||||
#include "renderer_api.h"
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "dynamic_libs.h"
 | 
					#include "dynamic_libs.h"
 | 
				
			||||||
 | 
					#include "gfx.h"
 | 
				
			||||||
 | 
					#include "renderer_api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
					/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
				
			||||||
 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
					 * 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",
 | 
					          "Select the render backend. Available options: [vk], Default: vk",
 | 
				
			||||||
          "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)                                            \
 | 
					#define RETRIEVE_SYMBOL(name, type)                                            \
 | 
				
			||||||
    g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vy" #name);          \
 | 
					    g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vy" #name);          \
 | 
				
			||||||
    if (!g_renderer.name) { \
 | 
					    if (!g_renderer.name) {                                                    \
 | 
				
			||||||
        vyReportError(                                                         \
 | 
					        vyReportError(                                                         \
 | 
				
			||||||
            "GFX",                                                             \
 | 
					            "GFX",                                                             \
 | 
				
			||||||
            "Unable to retrieve renderer function %s from backend %s",         \
 | 
					            "Unable to retrieve renderer function %s from backend %s",         \
 | 
				
			||||||
            #name, rt_Renderer.s); \
 | 
					            #name,                                                             \
 | 
				
			||||||
 | 
					            rt_Renderer.s);                                                    \
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (strcmp(rt_Renderer.s, "vk") == 0) {
 | 
					    if (strcmp(rt_Renderer.s, "vk") == 0) {
 | 
				
			||||||
@ -50,14 +51,16 @@ static bool LoadRenderer(void)
 | 
				
			|||||||
                        vy_compile_graphics_pipeline_fn);
 | 
					                        vy_compile_graphics_pipeline_fn);
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    } else {
 | 
					    } 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;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#undef RETRIEVE_SYMBOL
 | 
					#undef RETRIEVE_SYMBOL
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyRegisterRendererCVars(void)
 | 
					VY_DLLEXPORT void vyRegisterRendererCVars(void) {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (!_renderer_loaded) {
 | 
					    if (!_renderer_loaded) {
 | 
				
			||||||
        if (!LoadRenderer())
 | 
					        if (!LoadRenderer())
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -73,7 +76,7 @@ VY_DLLEXPORT bool vyInitGFX(vy_renderer_init_info *renderer_info) {
 | 
				
			|||||||
        g_renderer.RegisterCVars();
 | 
					        g_renderer.RegisterCVars();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (g_renderer.Init(renderer_info) != 0)
 | 
					    if (g_renderer.Init(renderer_info) != VY_SUCCESS)
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Init shader programs */
 | 
					    /* Init shader programs */
 | 
				
			||||||
 | 
				
			|||||||
@ -6,10 +6,11 @@
 | 
				
			|||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime.h"
 | 
					 | 
				
			||||||
#include "fio.h"
 | 
					#include "fio.h"
 | 
				
			||||||
#include "gfx.h"
 | 
					#include "gfx.h"
 | 
				
			||||||
 | 
					#include "handles.h"
 | 
				
			||||||
#include "renderer_api.h"
 | 
					#include "renderer_api.h"
 | 
				
			||||||
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    VY_STMT_FORM_VALUE,
 | 
					    VY_STMT_FORM_VALUE,
 | 
				
			||||||
@ -289,9 +290,9 @@ static vy_fio_handle DispatchShaderRead(const char *shader,
 | 
				
			|||||||
    return DispatchFileRead(path->value);
 | 
					    return DispatchFileRead(path->value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
 | 
					static vy_gfx_pipeline_handle CreatePipeline(vy_parse_state *state,
 | 
				
			||||||
                                         const char *file_path,
 | 
					                                             const char *file_path,
 | 
				
			||||||
                                         unsigned int root_list) {
 | 
					                                             unsigned int root_list) {
 | 
				
			||||||
    /* Process the data */
 | 
					    /* Process the data */
 | 
				
			||||||
    vy_fio_handle vertex_read =
 | 
					    vy_fio_handle vertex_read =
 | 
				
			||||||
        DispatchShaderRead("vertex", state, root_list, file_path);
 | 
					        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(vertex_read);
 | 
				
			||||||
            vyAbortFIO(fragment_read);
 | 
					            vyAbortFIO(fragment_read);
 | 
				
			||||||
            vyAbortFIO(compute_read);
 | 
					            vyAbortFIO(compute_read);
 | 
				
			||||||
            return (vy_gfx_pipeline_id){0};
 | 
					            return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        while (!vyIsFIOFinished(compute_read)) {
 | 
					        while (!vyIsFIOFinished(compute_read)) {
 | 
				
			||||||
            /* wait */
 | 
					            /* wait */
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        vy_file_buffer compute_code;
 | 
					        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",
 | 
					            vyReportError("GFX",
 | 
				
			||||||
                          "Failed to load compute shader required by: %s",
 | 
					                          "Failed to load compute shader required by: %s",
 | 
				
			||||||
                          file_path);
 | 
					                          file_path);
 | 
				
			||||||
            return (vy_gfx_pipeline_id){0};
 | 
					            return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        vy_compute_pipeline_info info;
 | 
					        vy_compute_pipeline_info info;
 | 
				
			||||||
        info.compute_source         = compute_code.data;
 | 
					        info.compute_source        = compute_code.data;
 | 
				
			||||||
        info.compute_source_length  = compute_code.size;
 | 
					        info.compute_source_length = compute_code.size;
 | 
				
			||||||
        vy_gfx_pipeline_id pipeline = g_renderer.CompileComputePipeline(&info);
 | 
					        vy_gfx_pipeline_handle pipeline =
 | 
				
			||||||
 | 
					            g_renderer.CompileComputePipeline(&info);
 | 
				
			||||||
        vyFreeFileBuffer(compute_code);
 | 
					        vyFreeFileBuffer(compute_code);
 | 
				
			||||||
        return pipeline;
 | 
					        return pipeline;
 | 
				
			||||||
    } else if (vertex_read || fragment_read) {
 | 
					    } else if (vertex_read || fragment_read) {
 | 
				
			||||||
@ -336,7 +339,7 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
 | 
				
			|||||||
            vyAbortFIO(vertex_read);
 | 
					            vyAbortFIO(vertex_read);
 | 
				
			||||||
            vyAbortFIO(fragment_read);
 | 
					            vyAbortFIO(fragment_read);
 | 
				
			||||||
            vyAbortFIO(compute_read);
 | 
					            vyAbortFIO(compute_read);
 | 
				
			||||||
            return (vy_gfx_pipeline_id){0};
 | 
					            return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (!vertex_read || !fragment_read) {
 | 
					        if (!vertex_read || !fragment_read) {
 | 
				
			||||||
            vyReportError("GFX",
 | 
					            vyReportError("GFX",
 | 
				
			||||||
@ -346,7 +349,7 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
 | 
				
			|||||||
            vyAbortFIO(vertex_read);
 | 
					            vyAbortFIO(vertex_read);
 | 
				
			||||||
            vyAbortFIO(fragment_read);
 | 
					            vyAbortFIO(fragment_read);
 | 
				
			||||||
            vyAbortFIO(compute_read);
 | 
					            vyAbortFIO(compute_read);
 | 
				
			||||||
            return (vy_gfx_pipeline_id){0};
 | 
					            return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        vy_graphics_pipeline_info info;
 | 
					        vy_graphics_pipeline_info info;
 | 
				
			||||||
@ -356,13 +359,14 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
 | 
				
			|||||||
        int remaining = 2;
 | 
					        int remaining = 2;
 | 
				
			||||||
        while (remaining > 0) {
 | 
					        while (remaining > 0) {
 | 
				
			||||||
            if (vyIsFIOFinished(vertex_read)) {
 | 
					            if (vyIsFIOFinished(vertex_read)) {
 | 
				
			||||||
                if (!vyRetrieveReadBuffer(vertex_read, &vertex_code) || !vyWasFileBufferSuccessful(&vertex_code)) {
 | 
					                if (!vyRetrieveReadBuffer(vertex_read, &vertex_code) ||
 | 
				
			||||||
 | 
					                    !vyWasFileBufferSuccessful(&vertex_code)) {
 | 
				
			||||||
                    vyReportError(
 | 
					                    vyReportError(
 | 
				
			||||||
                        "GFX",
 | 
					                        "GFX",
 | 
				
			||||||
                        "Failed to load vertex shader required by: %s",
 | 
					                        "Failed to load vertex shader required by: %s",
 | 
				
			||||||
                        file_path);
 | 
					                        file_path);
 | 
				
			||||||
                    vyFreeFileBuffer(fragment_code);
 | 
					                    vyFreeFileBuffer(fragment_code);
 | 
				
			||||||
                    return (vy_gfx_pipeline_id){0};
 | 
					                    return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                info.vertex_source        = vertex_code.data;
 | 
					                info.vertex_source        = vertex_code.data;
 | 
				
			||||||
                info.vertex_source_length = vertex_code.size;
 | 
					                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 (vyIsFIOFinished(fragment_read)) {
 | 
				
			||||||
                if (!vyRetrieveReadBuffer(fragment_read, &fragment_code) || !vyWasFileBufferSuccessful(&fragment_code)) {
 | 
					                if (!vyRetrieveReadBuffer(fragment_read, &fragment_code) ||
 | 
				
			||||||
 | 
					                    !vyWasFileBufferSuccessful(&fragment_code)) {
 | 
				
			||||||
                    vyReportError(
 | 
					                    vyReportError(
 | 
				
			||||||
                        "GFX",
 | 
					                        "GFX",
 | 
				
			||||||
                        "Failed to load fragment shader required by: %s",
 | 
					                        "Failed to load fragment shader required by: %s",
 | 
				
			||||||
                        file_path);
 | 
					                        file_path);
 | 
				
			||||||
                    vyFreeFileBuffer(vertex_code);
 | 
					                    vyFreeFileBuffer(vertex_code);
 | 
				
			||||||
                    return (vy_gfx_pipeline_id){0};
 | 
					                    return (vy_gfx_pipeline_handle){0};
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                info.fragment_source        = fragment_code.data;
 | 
					                info.fragment_source        = fragment_code.data;
 | 
				
			||||||
                info.fragment_source_length = fragment_code.size;
 | 
					                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(vertex_code);
 | 
				
			||||||
        vyFreeFileBuffer(fragment_code);
 | 
					        vyFreeFileBuffer(fragment_code);
 | 
				
			||||||
        return pipeline;
 | 
					        return pipeline;
 | 
				
			||||||
@ -399,7 +405,7 @@ static vy_gfx_pipeline_id CreatePipeline(vy_parse_state *state,
 | 
				
			|||||||
        vyAbortFIO(fragment_read);
 | 
					        vyAbortFIO(fragment_read);
 | 
				
			||||||
        vyAbortFIO(compute_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) {
 | 
					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);
 | 
					    DbgPrintShaderFile(&state, root_list, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    shader->pipeline = CreatePipeline(&state, file_path, root_list);
 | 
					    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;
 | 
					        result = false;
 | 
				
			||||||
        goto out;
 | 
					        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 <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gfx.h"
 | 
					#include "gfx.h"
 | 
				
			||||||
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
struct HINSTANCE__;
 | 
					struct HINSTANCE__;
 | 
				
			||||||
@ -38,11 +39,11 @@ typedef struct {
 | 
				
			|||||||
} vy_graphics_pipeline_info;
 | 
					} vy_graphics_pipeline_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void vy_register_renderer_cvars_fn(void);
 | 
					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 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);
 | 
					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);
 | 
					vy_compile_graphics_pipeline_fn(const vy_graphics_pipeline_info *info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,14 +6,17 @@
 | 
				
			|||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
        #define VY_DLLEXPORT __declspec(dllexport)
 | 
					    #define VY_DLLEXPORT __declspec(dllexport)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        #define VY_DLLEXPORT
 | 
					    #define VY_DLLEXPORT
 | 
				
			||||||
#endif
 | 
					#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]))
 | 
					#define VY_ARRAY_COUNT(x) (sizeof((x)) / sizeof((x)[0]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef unsigned int vy_result;
 | 
				
			||||||
 | 
					#define VY_SUCCESS 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    const char *start;
 | 
					    const char *start;
 | 
				
			||||||
    unsigned int length;
 | 
					    unsigned int length;
 | 
				
			||||||
 | 
				
			|||||||
@ -17,4 +17,25 @@ VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT bool vyUnlockMutex(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
 | 
					#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 "runtime.h"
 | 
				
			||||||
 | 
					#include "threading.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    #define WIN32_LEAN_AND_MEAN
 | 
					    #define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
@ -44,8 +44,7 @@ VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex) {
 | 
				
			|||||||
VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
 | 
					VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
 | 
				
			||||||
    return WaitForSingleObject(mutex->handle, INFINITE) == WAIT_OBJECT_0;
 | 
					    return WaitForSingleObject(mutex->handle, INFINITE) == WAIT_OBJECT_0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					v VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
 | 
				
			||||||
VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
 | 
					 | 
				
			||||||
    return ReleaseMutex(mutex->handle) != 0;
 | 
					    return ReleaseMutex(mutex->handle) != 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -61,30 +60,38 @@ struct vy_mutex_s {
 | 
				
			|||||||
static vy_mutex _mutex[MAX_MUTEX];
 | 
					static vy_mutex _mutex[MAX_MUTEX];
 | 
				
			||||||
static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
					static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
				
			||||||
static ptrdiff_t _next           = 0;
 | 
					static ptrdiff_t _next           = 0;
 | 
				
			||||||
 | 
					static pthread_mutex_t _guard    = PTHREAD_MUTEX_INITIALIZER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
					VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
				
			||||||
 | 
					    pthread_mutex_lock(&_guard);
 | 
				
			||||||
    if (_first_reusable < MAX_MUTEX) {
 | 
					    if (_first_reusable < MAX_MUTEX) {
 | 
				
			||||||
        vy_mutex *mtx   = &_mutex[_first_reusable];
 | 
					        vy_mutex *mtx   = &_mutex[_first_reusable];
 | 
				
			||||||
        _first_reusable = mtx->next_reusable;
 | 
					        _first_reusable = mtx->next_reusable;
 | 
				
			||||||
 | 
					        pthread_mutex_unlock(&_guard);
 | 
				
			||||||
        return mtx;
 | 
					        return mtx;
 | 
				
			||||||
    } else if (_next < MAX_MUTEX) {
 | 
					    } else if (_next < MAX_MUTEX) {
 | 
				
			||||||
        vy_mutex *mtx = &_mutex[_next];
 | 
					        vy_mutex *mtx = &_mutex[_next];
 | 
				
			||||||
        if (pthread_mutex_init(&mtx->handle, NULL) != 0) {
 | 
					        if (pthread_mutex_init(&mtx->handle, NULL) != 0) {
 | 
				
			||||||
            vyLog("core", "Mutex creation failed");
 | 
					            vyLog("core", "Mutex creation failed");
 | 
				
			||||||
 | 
					            pthread_mutex_unlock(&_guard);
 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        mtx->next_reusable = MAX_MUTEX;
 | 
					        mtx->next_reusable = MAX_MUTEX;
 | 
				
			||||||
        ++_next;
 | 
					        ++_next;
 | 
				
			||||||
 | 
					        pthread_mutex_unlock(&_guard);
 | 
				
			||||||
        return mtx;
 | 
					        return mtx;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vyReportError("core", "Ran out of mutex objects");
 | 
					    vyReportError("core", "Ran out of mutex objects");
 | 
				
			||||||
 | 
					    pthread_mutex_unlock(&_guard);
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex) {
 | 
					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;
 | 
					    mutex->next_reusable = _first_reusable;
 | 
				
			||||||
    _first_reusable      = index;
 | 
					    _first_reusable      = index;
 | 
				
			||||||
 | 
					    pthread_mutex_unlock(&_guard);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
 | 
					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