Compare commits

..

2 Commits

Author SHA1 Message Date
noah metz e4649bc5f1 Fixed vertex shader test 2024-10-24 20:50:27 -06:00
noah metz cc06265ca6 Pass time to shaders 2024-10-24 20:49:59 -06:00
11 changed files with 204 additions and 167 deletions

@ -6,10 +6,7 @@
VkResult draw_frame( VkResult draw_frame(
RenderContext* context, RenderContext* context,
UIContext* ui,
double time); double time);
VkResult record_draw_commands(
RenderContext* context,
UIContext* ui_context);
#endif #endif

@ -24,20 +24,20 @@
#include <cglm/quat.h> #include <cglm/quat.h>
#include <cglm/cam.h> #include <cglm/cam.h>
typedef struct QueueStruct { typedef struct GPUQueueStruct {
VkQueue handle; VkQueue handle;
uint32_t family; uint32_t family;
uint32_t index; uint32_t index;
} Queue; } GPUQueue;
VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool); VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool);
VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, Queue transfer_queue); VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, GPUQueue transfer_queue);
void command_copy_buffer(VkCommandBuffer command_buffer, VkBuffer src, VkBuffer dst, VkDeviceSize src_offset, VkDeviceSize dst_offset, VkDeviceSize size); void command_copy_buffer(VkCommandBuffer command_buffer, VkBuffer src, VkBuffer dst, VkDeviceSize src_offset, VkDeviceSize dst_offset, VkDeviceSize size);
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags); VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, GPUQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags);
#define VK_RESULT(x) {\ #define VK_RESULT(x) {\
result = x;\ result = x;\
@ -66,9 +66,9 @@ typedef struct RenderContextStruct {
VkPhysicalDevice physical_device; VkPhysicalDevice physical_device;
VkPhysicalDeviceMemoryProperties memories; VkPhysicalDeviceMemoryProperties memories;
VkSurfaceKHR surface; VkSurfaceKHR surface;
Queue graphics_queue; GPUQueue graphics_queue;
Queue present_queue; GPUQueue present_queue;
Queue transfer_queue; GPUQueue transfer_queue;
VkDevice device; VkDevice device;
VmaAllocator allocator; VmaAllocator allocator;

@ -38,6 +38,12 @@ typedef struct DispatchCommandStruct {
uint32_t z; uint32_t z;
} DispatchCommand; } DispatchCommand;
typedef struct UIPushConstantStruct {
VkDeviceAddress layer;
float time;
float pad;
} UIPushConstant;
typedef struct GPUFontStruct { typedef struct GPUFontStruct {
VkDeviceAddress symbol_list; VkDeviceAddress symbol_list;
uint32_t num_symbols; uint32_t num_symbols;
@ -91,8 +97,10 @@ typedef struct GPUDrawableStruct {
vec2 size; vec2 size;
vec4 color; vec4 color;
uint32_t type; uint32_t type;
uint32_t code; uint32_t var1;
uint32_t index; uint32_t var2;
float var3;
float var4;
uint32_t id; uint32_t id;
} GPUDrawable; } GPUDrawable;
@ -147,6 +155,8 @@ typedef struct GPUContainerStruct {
vec2 offset; vec2 offset;
vec2 size; vec2 size;
uint32_t anchor; uint32_t anchor;
VkDeviceAddress context;
} GPUContainer; } GPUContainer;
typedef struct ContainerStruct { typedef struct ContainerStruct {

@ -3,17 +3,12 @@
#include "ui_common.glsl" #include "ui_common.glsl"
layout(std430, push_constant) uniform PushConstant {
Context context;
Layer layer;
} pc;
layout(local_size_x = 1) in; layout(local_size_x = 1) in;
void main() { void main() {
uint gID = gl_GlobalInvocationID.x; uint gID = gl_GlobalInvocationID.x;
String string = pc.layer.strings.s[gID]; String string = pc.layer.strings.s[gID];
Font font = pc.context.fonts.f[string.font]; Font font = pc.layer.container.context.fonts.f[string.font];
uint buffer_pos = atomicAdd(pc.layer.draw.instance_count, string.len); uint buffer_pos = atomicAdd(pc.layer.draw.instance_count, string.len);
vec2 pen = vec2(0.0, 0.0); vec2 pen = vec2(0.0, 0.0);
@ -24,8 +19,8 @@ void main() {
pen += string.size*symbol.advance; pen += string.size*symbol.advance;
pc.layer.drawables.d[buffer_pos + i].size = vec2(string.size, string.size); pc.layer.drawables.d[buffer_pos + i].size = vec2(string.size, string.size);
pc.layer.drawables.d[buffer_pos + i].color = string.color; pc.layer.drawables.d[buffer_pos + i].color = string.color;
pc.layer.drawables.d[buffer_pos + i].code = pc.layer.codes.c[string.offset + i]; pc.layer.drawables.d[buffer_pos + i].var1 = pc.layer.codes.c[string.offset + i];
pc.layer.drawables.d[buffer_pos + i].index = string.font; pc.layer.drawables.d[buffer_pos + i].var2 = string.font;
pc.layer.drawables.d[buffer_pos + i].type = 1; pc.layer.drawables.d[buffer_pos + i].type = 1;
} }
} }

@ -4,11 +4,6 @@
#include "ui_common.glsl" #include "ui_common.glsl"
layout(std430, push_constant) uniform PushConstant {
Context context;
Layer layer;
} pc;
layout(set = 0, binding = 0) uniform sampler font_samplers[]; layout(set = 0, binding = 0) uniform sampler font_samplers[];
layout(set = 1, binding = 0) uniform texture2DArray font_textures[]; layout(set = 1, binding = 0) uniform texture2DArray font_textures[];
@ -25,7 +20,7 @@ layout(location = 5) flat in vec2 container_offset;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
void main() { void main() {
vec2 pos = (gl_FragCoord.xy - vec2(0.5, 0.5))/pc.context.scale; vec2 pos = (gl_FragCoord.xy - vec2(0.5, 0.5))/pc.layer.container.context.scale;
vec2 min = container_offset; vec2 min = container_offset;
vec2 max = min + pc.layer.container.size; vec2 max = min + pc.layer.container.size;
if(pos.x < min.x || pos.y < min.y if(pos.x < min.x || pos.y < min.y

@ -3,15 +3,10 @@
#include "ui_common.glsl" #include "ui_common.glsl"
layout(std430, push_constant) uniform PushConstant {
Context context;
Layer layer;
} pc;
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec2 fragUV; layout(location = 1) out vec2 fragUV;
layout(location = 2) out flat uint code; layout(location = 2) out flat uint var1;
layout(location = 3) out flat uint index; layout(location = 3) out flat uint var2;
layout(location = 4) out flat uint type; layout(location = 4) out flat uint type;
layout(location = 5) out flat vec2 container_offset; layout(location = 5) out flat vec2 container_offset;
@ -35,24 +30,23 @@ void main() {
// Top Right // Top Right
if(pc.layer.container.anchor == 1) { if(pc.layer.container.anchor == 1) {
container_offset = pc.layer.container.offset + vec2(pc.context.extent.x - pc.layer.container.size.x, 0); container_offset = pc.layer.container.offset + vec2(pc.layer.container.context.extent.x - pc.layer.container.size.x, 0);
} }
// Bottom Left // Bottom Left
if(pc.layer.container.anchor == 2) { if(pc.layer.container.anchor == 2) {
container_offset = pc.layer.container.offset + vec2(0, pc.context.extent.y - pc.layer.container.size.y); container_offset = pc.layer.container.offset + vec2(0, pc.layer.container.context.extent.y - pc.layer.container.size.y);
} }
// Bottom Right // Bottom Right
if(pc.layer.container.anchor == 3) { if(pc.layer.container.anchor == 3) {
container_offset = pc.layer.container.offset + vec2(pc.context.extent.x - pc.layer.container.size.x, pc.context.extent.y - pc.layer.container.size.y); container_offset = pc.layer.container.offset + vec2(pc.layer.container.context.extent.x - pc.layer.container.size.x, pc.layer.container.context.extent.y - pc.layer.container.size.y);
} }
if(drawable.type == 1){ if(drawable.type == 1){
// Glyph // Glyph
Font font = pc.context.fonts.f[drawable.index]; Font font = pc.layer.container.context.fonts.f[drawable.var2];
Symbol symbol = font.symbols.s[drawable.code]; Symbol symbol = font.symbols.s[drawable.var1];
fragUV = pos * vec2(symbol.width, symbol.height); fragUV = pos * vec2(symbol.width, symbol.height);
pos = pos * vec2(symbol.width, symbol.height) + vec2(symbol.left, -symbol.top); pos = pos * vec2(symbol.width, symbol.height) + vec2(symbol.left, -symbol.top);
@ -60,11 +54,11 @@ void main() {
fragUV = pos; fragUV = pos;
} }
gl_Position = vec4((pos * drawable.size + drawable.pos + container_offset) * pc.context.screen * 2, 0.0, 1.0) - vec4(1.0, 1.0, 0.0, 0.0); gl_Position = vec4((pos * drawable.size + drawable.pos + container_offset) * pc.layer.container.context.screen * 2, 0.0, 1.0) - vec4(1.0, 1.0, 0.0, 0.0);
fragColor = drawable.color; fragColor = drawable.color;
code = drawable.code;
type = drawable.type; type = drawable.type;
index = drawable.index; var1 = drawable.var1;
var2 = drawable.var2;
} }

@ -61,8 +61,10 @@ struct Drawable {
vec2 size; vec2 size;
vec4 color; vec4 color;
uint type; uint type;
uint code; uint var1;
uint index; uint var2;
float var3;
float var4;
uint id; uint id;
}; };
@ -70,10 +72,19 @@ layout(std430, buffer_reference) readonly buffer DrawableList {
Drawable d[]; Drawable d[];
}; };
layout(std430, buffer_reference) buffer Context {
FontList fonts;
vec2 screen;
vec2 extent;
vec2 scale;
};
layout(std430, buffer_reference) readonly buffer Container { layout(std430, buffer_reference) readonly buffer Container {
vec2 offset; vec2 offset;
vec2 size; vec2 size;
uint anchor; uint anchor;
Context context;
}; };
layout(std430, buffer_reference) readonly buffer Layer { layout(std430, buffer_reference) readonly buffer Layer {
@ -92,9 +103,7 @@ layout(std430, buffer_reference) readonly buffer Layer {
Container container; Container container;
}; };
layout(std430, buffer_reference) buffer Context { layout(std430, push_constant) uniform PushConstant {
FontList fonts; Layer layer;
vec2 screen; float time;
vec2 extent; } pc;
vec2 scale;
};

@ -8,14 +8,17 @@
* - ui_context->containers[*].layers[*].address <- device address * - ui_context->containers[*].layers[*].address <- device address
* Basically, needs to be re-run whenever the number of layers/containers changes * Basically, needs to be re-run whenever the number of layers/containers changes
*/ */
void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui_context) { void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui_context, double time) {
VkDeviceAddress push[2] = {ui_context->address, 0}; UIPushConstant push = {
.time = (float)time,
.layer = 0,
};
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->string_pipeline.pipeline); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->string_pipeline.pipeline);
for(uint32_t i = 0; i < ui_context->max_containers; i++) { for(uint32_t i = 0; i < ui_context->max_containers; i++) {
if(ui_context->containers[i].id != 0x00000000) { if(ui_context->containers[i].id != 0x00000000) {
for(uint32_t j = 0; j < ui_context->containers[i].layer_count; j++) { for(uint32_t j = 0; j < ui_context->containers[i].layer_count; j++) {
push[1] = ui_context->containers[i].layers[j].address; push.layer = ui_context->containers[i].layers[j].address;
VkBufferMemoryBarrier draw_command_barrier_1 = { VkBufferMemoryBarrier draw_command_barrier_1 = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.buffer = ui_context->containers[i].layers[j].layer, .buffer = ui_context->containers[i].layers[j].layer,
@ -35,7 +38,7 @@ void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui_context) {
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT, .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
}; };
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 1, &draw_command_barrier_2, 0, NULL); vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 1, &draw_command_barrier_2, 0, NULL);
vkCmdPushConstants(command_buffer, ui_context->string_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 16, push); vkCmdPushConstants(command_buffer, ui_context->string_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 16, &push);
vkCmdDispatchIndirect(command_buffer, ui_context->containers[i].layers[j].layer, offsetof(GPULayer, dispatch_strings)); vkCmdDispatchIndirect(command_buffer, ui_context->containers[i].layers[j].layer, offsetof(GPULayer, dispatch_strings));
VkBufferMemoryBarrier draw_command_barrier_3 = { VkBufferMemoryBarrier draw_command_barrier_3 = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
@ -68,8 +71,11 @@ void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui_context) {
* - ui_context->containers[*].layers[*].address <- device address * - ui_context->containers[*].layers[*].address <- device address
* Basically, needs to be re-run whenever the number of layers/containers changes * Basically, needs to be re-run whenever the number of layers/containers changes
*/ */
void record_ui_draw(VkCommandBuffer command_buffer, UIContext* ui_context) { void record_ui_draw(VkCommandBuffer command_buffer, UIContext* ui_context, double time) {
VkDeviceAddress push[2] = {ui_context->address, 0}; UIPushConstant push = {
.time = (float)time,
.layer = 0,
};
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.pipeline); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.pipeline);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.layout, 0, 1, &ui_context->font_samplers, 0, NULL); vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->pipeline.layout, 0, 1, &ui_context->font_samplers, 0, NULL);
@ -79,19 +85,36 @@ void record_ui_draw(VkCommandBuffer command_buffer, UIContext* ui_context) {
for(uint32_t i = 0; i < ui_context->max_containers; i++) { for(uint32_t i = 0; i < ui_context->max_containers; i++) {
if(ui_context->containers[i].id != 0x00000000) { if(ui_context->containers[i].id != 0x00000000) {
for(uint32_t j = 0; j < ui_context->containers[i].layer_count; j++) { for(uint32_t j = 0; j < ui_context->containers[i].layer_count; j++) {
push[1] = ui_context->containers[i].layers[j].address; push.layer = ui_context->containers[i].layers[j].address;
vkCmdPushConstants(command_buffer, ui_context->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, push); vkCmdPushConstants(command_buffer, ui_context->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, &push);
vkCmdDrawIndirect(command_buffer, ui_context->containers[i].layers[j].layer, offsetof(GPULayer, draw), 1, 0); vkCmdDrawIndirect(command_buffer, ui_context->containers[i].layers[j].layer, offsetof(GPULayer, draw), 1, 0);
} }
} }
} }
} }
VkResult record_draw_commands( VkResult draw_frame(
RenderContext* context, RenderContext* context,
UIContext* ui_context) { UIContext* ui,
double time) {
VkResult result; VkResult result;
for(uint32_t image_index = 0; image_index < context->swapchain_image_count; image_index++) {
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
if(result != VK_SUCCESS) {
return result;
}
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
if(result != VK_SUCCESS) {
return result;
}
uint32_t image_index;
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
if(result != VK_SUCCESS) {
return result;
}
VkCommandBuffer command_buffer = context->swapchain_command_buffers[image_index]; VkCommandBuffer command_buffer = context->swapchain_command_buffers[image_index];
VK_RESULT(vkResetCommandBuffer(command_buffer, 0)); VK_RESULT(vkResetCommandBuffer(command_buffer, 0));
@ -125,42 +148,16 @@ VkResult record_draw_commands(
.pClearValues = clear_values, .pClearValues = clear_values,
}; };
record_ui_compute(command_buffer, ui_context); record_ui_compute(command_buffer, ui, time);
vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
// Render World // Render World
vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE); vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE);
// Render UI // Render UI
record_ui_draw(command_buffer, ui_context); record_ui_draw(command_buffer, ui, time);
vkCmdEndRenderPass(command_buffer); vkCmdEndRenderPass(command_buffer);
VK_RESULT(vkEndCommandBuffer(command_buffer)); VK_RESULT(vkEndCommandBuffer(command_buffer));
}
return VK_SUCCESS;
}
VkResult draw_frame(
RenderContext* context,
double time) {
(void)time;
VkResult result;
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
if(result != VK_SUCCESS) {
return result;
}
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
if(result != VK_SUCCESS) {
return result;
}
uint32_t image_index;
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
if(result != VK_SUCCESS) {
return result;
}
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submit_info = { VkSubmitInfo submit_info = {

@ -58,7 +58,7 @@ GLFWwindow* init_window() {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
// TODO: recreate the framebuffer on resize // TODO: recreate the framebuffer on resize
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
GLFWwindow* window = glfwCreateWindow(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT, "roleplay", 0, 0); GLFWwindow* window = glfwCreateWindow(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT, "roleplay", 0, 0);
glfwSetWindowSizeLimits(window, WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE); glfwSetWindowSizeLimits(window, WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE);
@ -232,7 +232,7 @@ VkResult get_best_physical_device(VkInstance instance, VkPhysicalDevice* device)
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult create_logical_device(VkPhysicalDevice physical_device, VkSurfaceKHR surface, Queue* graphics_queue, Queue* present_queue, Queue* transfer_queue, VkDevice* device) { VkResult create_logical_device(VkPhysicalDevice physical_device, VkSurfaceKHR surface, GPUQueue* graphics_queue, GPUQueue* present_queue, GPUQueue* transfer_queue, VkDevice* device) {
if(graphics_queue == NULL || present_queue == NULL || transfer_queue == NULL || device == NULL) { if(graphics_queue == NULL || present_queue == NULL || transfer_queue == NULL || device == NULL) {
return VK_ERROR_VALIDATION_FAILED_EXT; return VK_ERROR_VALIDATION_FAILED_EXT;
} }
@ -778,7 +778,7 @@ VkCommandBuffer* create_command_buffers(VkDevice device, VkCommandPool command_p
return command_buffers; return command_buffers;
} }
VkResult create_depth_image(VkDevice device, VkFormat depth_format, VkExtent2D swapchain_extent, VmaAllocator allocator, VkCommandPool extra_graphics_pool, Queue graphics_queue, VkImage* depth_image, VmaAllocation* depth_image_memory, VkImageView* depth_image_view) { VkResult create_depth_image(VkDevice device, VkFormat depth_format, VkExtent2D swapchain_extent, VmaAllocator allocator, VkCommandPool extra_graphics_pool, GPUQueue graphics_queue, VkImage* depth_image, VmaAllocation* depth_image_memory, VkImageView* depth_image_view) {
VkExtent3D depth_extent = { VkExtent3D depth_extent = {
.width = swapchain_extent.width, .width = swapchain_extent.width,
@ -1077,7 +1077,7 @@ VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_poo
return command_buffer; return command_buffer;
} }
VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, Queue transfer_queue) { VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, GPUQueue transfer_queue) {
VkResult result = vkEndCommandBuffer(command_buffer); VkResult result = vkEndCommandBuffer(command_buffer);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer); vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
@ -1110,7 +1110,7 @@ void command_copy_buffer(VkCommandBuffer command_buffer, VkBuffer src, VkBuffer
vkCmdCopyBuffer(command_buffer, src, dst, 1, &copy); vkCmdCopyBuffer(command_buffer, src, dst, 1, &copy);
} }
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags) { VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, GPUQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags) {
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool); VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkImageMemoryBarrier barrier = { VkImageMemoryBarrier barrier = {

@ -1,3 +1,4 @@
#include "GLFW/glfw3.h"
#include "ui.h" #include "ui.h"
#include "gpu.h" #include "gpu.h"
#include "draw.h" #include "draw.h"
@ -6,6 +7,14 @@
#include "vk_mem_alloc.h" #include "vk_mem_alloc.h"
#include "vulkan/vk_enum_string_helper.h" #include "vulkan/vk_enum_string_helper.h"
#include "vulkan/vulkan_core.h" #include "vulkan/vulkan_core.h"
#include "pthread.h"
#include "stdatomic.h"
typedef struct ClientContextStruct {
GLFWwindow* window;
RenderContext render;
UIContext ui;
} ClientContext;
VkResult test_ui(RenderContext* render, UIContext* ui) { VkResult test_ui(RenderContext* render, UIContext* ui) {
VkResult result; VkResult result;
@ -35,21 +44,12 @@ VkResult test_ui(RenderContext* render, UIContext* ui) {
.length = strlen("Example Text"), .length = strlen("Example Text"),
.font = 2, .font = 2,
}, },
{
.pos = {0, 128},
.size = 32,
.color = {1.0, 1.0, 1.0, 1.0},
.offset = 3*strlen("Example Text"),
.length = strlen("Example Text"),
.font = 3,
},
}; };
uint32_t context_codes[256]; uint32_t context_codes[256];
map_string("Example Text", context_codes, 0, 0, ui); map_string("Example Text", context_codes, 0, 0, ui);
map_string("Example Text", context_codes, strlen("Example Text"), 1, ui); map_string("Example Text", context_codes, strlen("Example Text"), 1, ui);
map_string("Example Text", context_codes, 2*strlen("Example Text"), 2, ui); map_string("Example Text", context_codes, 2*strlen("Example Text"), 2, ui);
map_string("Example Text", context_codes, 3*strlen("Example Text"), 3, ui);
LayerInput context_layers[] = { LayerInput context_layers[] = {
{ {
@ -151,49 +151,56 @@ VkResult test_ui(RenderContext* render, UIContext* ui) {
VK_RESULT(create_container(&inventory_info, render, ui)); VK_RESULT(create_container(&inventory_info, render, ui));
VK_RESULT(create_container(&chat_info, render, ui)); VK_RESULT(create_container(&chat_info, render, ui));
VK_RESULT(record_draw_commands(render, ui));
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult render_thread(GLFWwindow* window, RenderContext* render) { // Threads:
// 1. render
VkResult result; // - Submits the draw buffer to the GPU as soon as it can
// 2. network
// - Handles packets to/from the network to/from the main thread
// 3. main
// - updates the data in the GPU that's being drawn from
// - updates the data in the GPU from network requests
//
// Data:
// Render thread reads Render and UI context
// Main thread reads and writes UI context
void* render_thread(void* data) {
ClientContext* context = (ClientContext*)data;
double last_frame_time = glfwGetTime(); double last_frame_time = glfwGetTime();
while(glfwWindowShouldClose(window) == 0) { while(glfwWindowShouldClose(context->window) == 0) {
glfwPollEvents();
double frame_time = glfwGetTime(); double frame_time = glfwGetTime();
double delta_time = frame_time - last_frame_time; double delta_time = frame_time - last_frame_time;
(void)delta_time; (void)delta_time;
result = draw_frame(render, frame_time);
VkResult result = draw_frame(&context->render, &context->ui, frame_time);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result)); fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result));
return result; glfwDestroyWindow(context->window);
} }
last_frame_time = frame_time; last_frame_time = frame_time;
} }
return 0;
return NULL;
} }
typedef enum ClientAuthStateEnum { void* network_thread(void* data) {
AUTH_SAVED, ClientContext* context = (ClientContext*)data;
AUTH_CREDENTIALS, (void)context;
AUTH_ATTEMPT,
AUTH_ERROR,
AUTH_SUCCESS,
} ClientAuthState;
typedef struct ClientStateStruct { return NULL;
}
} ClientState; int main_thread(void* data) {
ClientContext* context = (ClientContext*)data;
int logic_thread() { while(glfwWindowShouldClose(context->window) == 0) {
return 0; glfwPollEvents();
} }
int network_thread() {
return 0; return 0;
} }
@ -206,7 +213,10 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
} }
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
(void)mods; (void)mods;
(void)context;
switch(button) { switch(button) {
// Handle camera hover // Handle camera hover
case GLFW_MOUSE_BUTTON_MIDDLE: case GLFW_MOUSE_BUTTON_MIDDLE:
@ -218,6 +228,10 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
break; break;
case GLFW_MOUSE_BUTTON_LEFT: case GLFW_MOUSE_BUTTON_LEFT:
if(action == GLFW_PRESS) { if(action == GLFW_PRESS) {
// NOTE: this logic is the same as it would be for right-click(just with different outcomes), so dont repeat yourself
// 1. Search through the UI context for the first element that the contains the mouse point
// 2. If no UI element intersection, cast a ray through the world scene to find the "clicked entity"
// 3. Based on what was clicked, start the mouse click animation at the target area
} }
break; break;
case GLFW_MOUSE_BUTTON_RIGHT: case GLFW_MOUSE_BUTTON_RIGHT:
@ -240,35 +254,61 @@ void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
} }
int main() { int main() {
GLFWwindow* window = init_window(); ClientContext context = {};
if(window == NULL) { context.window = init_window();
if(context.window == NULL) {
return 1; return 1;
} }
glfwSetKeyCallback(window, key_callback); glfwSetWindowUserPointer(context.window, &context);
glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetKeyCallback(context.window, key_callback);
glfwSetScrollCallback(window, scroll_callback); glfwSetMouseButtonCallback(context.window, mouse_button_callback);
glfwSetCursorPosCallback(window, cursor_pos_callback); glfwSetScrollCallback(context.window, scroll_callback);
glfwSetCursorPosCallback(context.window, cursor_pos_callback);
RenderContext render = {};
UIContext ui = {};
int error;
VkResult result; VkResult result;
VK_RESULT(init_vulkan(window, &render)); VK_RESULT(init_vulkan(context.window, &context.render));
// TODO: make # of fonts/textures/containers scaling, recreate GPU buffers as necessary // TODO: make # of fonts/textures/containers scaling, recreate GPU buffers as necessary
VK_RESULT(create_ui_context(10, 10, 10, &render, &ui)); VK_RESULT(create_ui_context(10, 10, 10, &context.render, &context.ui));
////////////////////////////////// //////////////////////////////////
/// Test Code /// Test UI Code
////////////////////////////////// //////////////////////////////////
VK_RESULT(test_ui(&render, &ui)); VK_RESULT(test_ui(&context.render, &context.ui));
////////////////////////////////// //////////////////////////////////
if(render_thread(window, &render) != VK_SUCCESS) { // Start threads
return 3; pthread_t render_thread_handle;
pthread_t network_thread_handle;
error = pthread_create(&render_thread_handle, NULL, &render_thread, &context);
if(error != 0) {
return error;
}
error = pthread_create(&network_thread_handle, NULL, &network_thread, &context);
if(error != 0) {
return error;
}
error = main_thread(&context);
if(error != 0) {
return error;
}
error = pthread_join(render_thread_handle, NULL);
if(error != 0) {
return error;
}
error = pthread_join(network_thread_handle, NULL);
if(error != 0) {
return error;
} }
return 0; return 0;

@ -304,6 +304,7 @@ VkResult create_container(
context->containers[index].data.size[0] = container->size[0]; context->containers[index].data.size[0] = container->size[0];
context->containers[index].data.size[1] = container->size[1]; context->containers[index].data.size[1] = container->size[1];
context->containers[index].data.anchor = container->anchor; context->containers[index].data.anchor = container->anchor;
context->containers[index].data.context = context->address;
memcpy(mapped, &context->containers[index].data, sizeof(GPUContainer)); memcpy(mapped, &context->containers[index].data, sizeof(GPUContainer));
VkCommandBuffer command_buffer = command_begin_single(gpu->device, gpu->transfer_pool); VkCommandBuffer command_buffer = command_begin_single(gpu->device, gpu->transfer_pool);
@ -1111,7 +1112,6 @@ VkResult create_ui_context(
VK_RESULT(load_font(0, "fonts/eracake.ttf", 256, VK_TRUE, gpu, context)); VK_RESULT(load_font(0, "fonts/eracake.ttf", 256, VK_TRUE, gpu, context));
VK_RESULT(load_font(1, "fonts/yumoda.ttf", 256, VK_TRUE, gpu, context)); VK_RESULT(load_font(1, "fonts/yumoda.ttf", 256, VK_TRUE, gpu, context));
VK_RESULT(load_font(2, "fonts/runescape.ttf", 16, VK_FALSE, gpu, context)); VK_RESULT(load_font(2, "fonts/runescape.ttf", 16, VK_FALSE, gpu, context));
VK_RESULT(load_font(3, "fonts/apple_2.ttf", 256, VK_FALSE, gpu, context));
return VK_SUCCESS; return VK_SUCCESS;
} }